schannel: remove the BACKEND define kludge

Closes #8182
This commit is contained in:
Daniel Stenberg 2021-12-25 22:23:05 +01:00
parent 4a2ab69ab5
commit b8ef4a845b
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -147,8 +147,6 @@
#define ALG_CLASS_DHASH ALG_CLASS_HASH #define ALG_CLASS_DHASH ALG_CLASS_HASH
#endif #endif
#define BACKEND connssl->backend
static Curl_recv schannel_recv; static Curl_recv schannel_recv;
static Curl_send schannel_send; static Curl_send schannel_send;
@ -423,6 +421,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
PCCERT_CONTEXT client_certs[1] = { NULL }; PCCERT_CONTEXT client_certs[1] = { NULL };
SECURITY_STATUS sspi_status = SEC_E_OK; SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result; CURLcode result;
struct ssl_backend_data *backend = connssl->backend;
/* setup Schannel API options */ /* setup Schannel API options */
memset(&schannel_cred, 0, sizeof(schannel_cred)); memset(&schannel_cred, 0, sizeof(schannel_cred));
@ -430,7 +429,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
if(conn->ssl_config.verifypeer) { if(conn->ssl_config.verifypeer) {
#ifdef HAS_MANUAL_VERIFY_API #ifdef HAS_MANUAL_VERIFY_API
if(BACKEND->use_manual_cred_validation) if(backend->use_manual_cred_validation)
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
else else
#endif #endif
@ -503,7 +502,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
if(SSL_CONN_CONFIG(cipher_list)) { if(SSL_CONN_CONFIG(cipher_list)) {
result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list), result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
BACKEND->algIds); backend->algIds);
if(CURLE_OK != result) { if(CURLE_OK != result) {
failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
return result; return result;
@ -704,9 +703,9 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
#endif #endif
/* allocate memory for the re-usable credential handle */ /* allocate memory for the re-usable credential handle */
BACKEND->cred = (struct Curl_schannel_cred *) backend->cred = (struct Curl_schannel_cred *)
calloc(1, sizeof(struct Curl_schannel_cred)); calloc(1, sizeof(struct Curl_schannel_cred));
if(!BACKEND->cred) { if(!backend->cred) {
failf(data, "schannel: unable to allocate memory"); failf(data, "schannel: unable to allocate memory");
if(client_certs[0]) if(client_certs[0])
@ -714,14 +713,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
BACKEND->cred->refcount = 1; backend->cred->refcount = 1;
sspi_status = sspi_status =
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL, SECPKG_CRED_OUTBOUND, NULL,
&schannel_cred, NULL, NULL, &schannel_cred, NULL, NULL,
&BACKEND->cred->cred_handle, &backend->cred->cred_handle,
&BACKEND->cred->time_stamp); &backend->cred->time_stamp);
if(client_certs[0]) if(client_certs[0])
CertFreeCertificateContext(client_certs[0]); CertFreeCertificateContext(client_certs[0]);
@ -730,7 +729,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
char buffer[STRERROR_LEN]; char buffer[STRERROR_LEN];
failf(data, "schannel: AcquireCredentialsHandle failed: %s", failf(data, "schannel: AcquireCredentialsHandle failed: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
Curl_safefree(BACKEND->cred); Curl_safefree(backend->cred);
switch(sspi_status) { switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY: case SEC_E_INSUFFICIENT_MEMORY:
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -769,6 +768,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
TCHAR *host_name; TCHAR *host_name;
CURLcode result; CURLcode result;
char * const hostname = SSL_HOST_NAME(); char * const hostname = SSL_HOST_NAME();
struct ssl_backend_data *backend = connssl->backend;
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %hu (step 1/3)", "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
@ -785,20 +785,20 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN #ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
Also it doesn't seem to be supported for Wine, see curl bug #983. */ Also it doesn't seem to be supported for Wine, see curl bug #983. */
BACKEND->use_alpn = conn->bits.tls_enable_alpn && backend->use_alpn = conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")), !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") && "wine_get_version") &&
curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT, curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL); VERSION_GREATER_THAN_EQUAL);
#else #else
BACKEND->use_alpn = false; backend->use_alpn = false;
#endif #endif
#ifdef _WIN32_WCE #ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API #ifdef HAS_MANUAL_VERIFY_API
/* certificate validation on CE doesn't seem to work right; we'll /* certificate validation on CE doesn't seem to work right; we'll
* do it following a more manual process. */ * do it following a more manual process. */
BACKEND->use_manual_cred_validation = true; backend->use_manual_cred_validation = true;
#else #else
#error "compiler too old to support requisite manual cert verify for Win CE" #error "compiler too old to support requisite manual cert verify for Win CE"
#endif #endif
@ -807,7 +807,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) { VERSION_GREATER_THAN_EQUAL)) {
BACKEND->use_manual_cred_validation = true; backend->use_manual_cred_validation = true;
} }
else { else {
failf(data, "schannel: this version of Windows is too old to support " failf(data, "schannel: this version of Windows is too old to support "
@ -816,7 +816,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
} }
} }
else else
BACKEND->use_manual_cred_validation = false; backend->use_manual_cred_validation = false;
#else #else
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
failf(data, "schannel: CA cert support not built in"); failf(data, "schannel: CA cert support not built in");
@ -825,7 +825,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif #endif
#endif #endif
BACKEND->cred = NULL; backend->cred = NULL;
/* check for an existing re-usable credential handle */ /* check for an existing re-usable credential handle */
if(SSL_SET_OPTION(primary.sessionid)) { if(SSL_SET_OPTION(primary.sessionid)) {
@ -833,19 +833,19 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(!Curl_ssl_getsessionid(data, conn, if(!Curl_ssl_getsessionid(data, conn,
SSL_IS_PROXY() ? TRUE : FALSE, SSL_IS_PROXY() ? TRUE : FALSE,
(void **)&old_cred, NULL, sockindex)) { (void **)&old_cred, NULL, sockindex)) {
BACKEND->cred = old_cred; backend->cred = old_cred;
DEBUGF(infof(data, "schannel: re-using existing credential handle")); DEBUGF(infof(data, "schannel: re-using existing credential handle"));
/* increment the reference counter of the credential/session handle */ /* increment the reference counter of the credential/session handle */
BACKEND->cred->refcount++; backend->cred->refcount++;
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: incremented credential handle refcount = %d", "schannel: incremented credential handle refcount = %d",
BACKEND->cred->refcount)); backend->cred->refcount));
} }
Curl_ssl_sessionid_unlock(data); Curl_ssl_sessionid_unlock(data);
} }
if(!BACKEND->cred) { if(!backend->cred) {
result = schannel_acquire_credential_handle(data, conn, sockindex); result = schannel_acquire_credential_handle(data, conn, sockindex);
if(result != CURLE_OK) { if(result != CURLE_OK) {
return result; return result;
@ -862,7 +862,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
} }
#ifdef HAS_ALPN #ifdef HAS_ALPN
if(BACKEND->use_alpn) { if(backend->use_alpn) {
int cur = 0; int cur = 0;
int list_start_index = 0; int list_start_index = 0;
unsigned int *extension_len = NULL; unsigned int *extension_len = NULL;
@ -920,18 +920,18 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
InitSecBufferDesc(&outbuf_desc, &outbuf, 1); InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
/* security request flags */ /* security request flags */
BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM; ISC_REQ_STREAM;
if(!SSL_SET_OPTION(auto_client_cert)) { if(!SSL_SET_OPTION(auto_client_cert)) {
BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
} }
/* allocate memory for the security context handle */ /* allocate memory for the security context handle */
BACKEND->ctxt = (struct Curl_schannel_ctxt *) backend->ctxt = (struct Curl_schannel_ctxt *)
calloc(1, sizeof(struct Curl_schannel_ctxt)); calloc(1, sizeof(struct Curl_schannel_ctxt));
if(!BACKEND->ctxt) { if(!backend->ctxt) {
failf(data, "schannel: unable to allocate memory"); failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
@ -948,16 +948,16 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
us problems with inbuf regardless. https://github.com/curl/curl/issues/983 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/ */
sspi_status = s_pSecFn->InitializeSecurityContext( sspi_status = s_pSecFn->InitializeSecurityContext(
&BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0, &backend->cred->cred_handle, NULL, host_name, backend->req_flags, 0, 0,
(BACKEND->use_alpn ? &inbuf_desc : NULL), (backend->use_alpn ? &inbuf_desc : NULL),
0, &BACKEND->ctxt->ctxt_handle, 0, &backend->ctxt->ctxt_handle,
&outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
curlx_unicodefree(host_name); curlx_unicodefree(host_name);
if(sspi_status != SEC_I_CONTINUE_NEEDED) { if(sspi_status != SEC_I_CONTINUE_NEEDED) {
char buffer[STRERROR_LEN]; char buffer[STRERROR_LEN];
Curl_safefree(BACKEND->ctxt); Curl_safefree(backend->ctxt);
switch(sspi_status) { switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY: case SEC_E_INSUFFICIENT_MEMORY:
failf(data, "schannel: initial InitializeSecurityContext failed: %s", failf(data, "schannel: initial InitializeSecurityContext failed: %s",
@ -1001,10 +1001,10 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
DEBUGF(infof(data, "schannel: sent initial handshake data: " DEBUGF(infof(data, "schannel: sent initial handshake data: "
"sent %zd bytes", written)); "sent %zd bytes", written));
BACKEND->recv_unrecoverable_err = CURLE_OK; backend->recv_unrecoverable_err = CURLE_OK;
BACKEND->recv_sspi_close_notify = false; backend->recv_sspi_close_notify = false;
BACKEND->recv_connection_closed = false; backend->recv_connection_closed = false;
BACKEND->encdata_is_incomplete = false; backend->encdata_is_incomplete = false;
/* continue to second handshake step */ /* continue to second handshake step */
connssl->connecting_state = ssl_connect_2; connssl->connecting_state = ssl_connect_2;
@ -1029,6 +1029,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
bool doread; bool doread;
char * const hostname = SSL_HOST_NAME(); char * const hostname = SSL_HOST_NAME();
const char *pubkey_ptr; const char *pubkey_ptr;
struct ssl_backend_data *backend = connssl->backend;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
@ -1036,39 +1037,39 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
"schannel: SSL/TLS connection with %s port %hu (step 2/3)", "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
hostname, conn->remote_port)); hostname, conn->remote_port));
if(!BACKEND->cred || !BACKEND->ctxt) if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
/* buffer to store previously received and decrypted data */ /* buffer to store previously received and decrypted data */
if(!BACKEND->decdata_buffer) { if(!backend->decdata_buffer) {
BACKEND->decdata_offset = 0; backend->decdata_offset = 0;
BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
BACKEND->decdata_buffer = malloc(BACKEND->decdata_length); backend->decdata_buffer = malloc(backend->decdata_length);
if(!BACKEND->decdata_buffer) { if(!backend->decdata_buffer) {
failf(data, "schannel: unable to allocate memory"); failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
} }
/* buffer to store previously received and encrypted data */ /* buffer to store previously received and encrypted data */
if(!BACKEND->encdata_buffer) { if(!backend->encdata_buffer) {
BACKEND->encdata_is_incomplete = false; backend->encdata_is_incomplete = false;
BACKEND->encdata_offset = 0; backend->encdata_offset = 0;
BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
BACKEND->encdata_buffer = malloc(BACKEND->encdata_length); backend->encdata_buffer = malloc(backend->encdata_length);
if(!BACKEND->encdata_buffer) { if(!backend->encdata_buffer) {
failf(data, "schannel: unable to allocate memory"); failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
} }
/* if we need a bigger buffer to read a full message, increase buffer now */ /* if we need a bigger buffer to read a full message, increase buffer now */
if(BACKEND->encdata_length - BACKEND->encdata_offset < if(backend->encdata_length - backend->encdata_offset <
CURL_SCHANNEL_BUFFER_FREE_SIZE) { CURL_SCHANNEL_BUFFER_FREE_SIZE) {
/* increase internal encrypted data buffer */ /* increase internal encrypted data buffer */
size_t reallocated_length = BACKEND->encdata_offset + size_t reallocated_length = backend->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE; CURL_SCHANNEL_BUFFER_FREE_SIZE;
reallocated_buffer = realloc(BACKEND->encdata_buffer, reallocated_buffer = realloc(backend->encdata_buffer,
reallocated_length); reallocated_length);
if(!reallocated_buffer) { if(!reallocated_buffer) {
@ -1076,8 +1077,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
else { else {
BACKEND->encdata_buffer = reallocated_buffer; backend->encdata_buffer = reallocated_buffer;
BACKEND->encdata_length = reallocated_length; backend->encdata_length = reallocated_length;
} }
} }
@ -1086,10 +1087,10 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
if(doread) { if(doread) {
/* read encrypted handshake data from socket */ /* read encrypted handshake data from socket */
result = Curl_read_plain(conn->sock[sockindex], result = Curl_read_plain(conn->sock[sockindex],
(char *) (BACKEND->encdata_buffer + (char *) (backend->encdata_buffer +
BACKEND->encdata_offset), backend->encdata_offset),
BACKEND->encdata_length - backend->encdata_length -
BACKEND->encdata_offset, backend->encdata_offset,
&nread); &nread);
if(result == CURLE_AGAIN) { if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing) if(connssl->connecting_state != ssl_connect_2_writing)
@ -1105,18 +1106,18 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
} }
/* increase encrypted data buffer offset */ /* increase encrypted data buffer offset */
BACKEND->encdata_offset += nread; backend->encdata_offset += nread;
BACKEND->encdata_is_incomplete = false; backend->encdata_is_incomplete = false;
DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
} }
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu", "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length)); backend->encdata_offset, backend->encdata_length));
/* setup input buffers */ /* setup input buffers */
InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset), InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
curlx_uztoul(BACKEND->encdata_offset)); curlx_uztoul(backend->encdata_offset));
InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&inbuf_desc, inbuf, 2); InitSecBufferDesc(&inbuf_desc, inbuf, 2);
@ -1132,17 +1133,17 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
} }
/* copy received handshake data into input buffer */ /* copy received handshake data into input buffer */
memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer, memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
BACKEND->encdata_offset); backend->encdata_offset);
host_name = curlx_convert_UTF8_to_tchar(hostname); host_name = curlx_convert_UTF8_to_tchar(hostname);
if(!host_name) if(!host_name)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
sspi_status = s_pSecFn->InitializeSecurityContext( sspi_status = s_pSecFn->InitializeSecurityContext(
&BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, host_name, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL,
&outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp); &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
curlx_unicodefree(host_name); curlx_unicodefree(host_name);
@ -1151,7 +1152,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* check if the handshake was incomplete */ /* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
BACKEND->encdata_is_incomplete = true; backend->encdata_is_incomplete = true;
connssl->connecting_state = ssl_connect_2_reading; connssl->connecting_state = ssl_connect_2_reading;
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: received incomplete message, need more data")); "schannel: received incomplete message, need more data"));
@ -1162,8 +1163,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
the handshake without one. This will allow connections to servers which the handshake without one. This will allow connections to servers which
request a client certificate but do not require it. */ request a client certificate but do not require it. */
if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
!(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
connssl->connecting_state = ssl_connect_2_writing; connssl->connecting_state = ssl_connect_2_writing;
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: a client certificate has been requested")); "schannel: a client certificate has been requested"));
@ -1245,11 +1246,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
*/ */
/* check if the remaining data is less than the total amount /* check if the remaining data is less than the total amount
and therefore begins after the already processed data */ and therefore begins after the already processed data */
if(BACKEND->encdata_offset > inbuf[1].cbBuffer) { if(backend->encdata_offset > inbuf[1].cbBuffer) {
memmove(BACKEND->encdata_buffer, memmove(backend->encdata_buffer,
(BACKEND->encdata_buffer + BACKEND->encdata_offset) - (backend->encdata_buffer + backend->encdata_offset) -
inbuf[1].cbBuffer, inbuf[1].cbBuffer); inbuf[1].cbBuffer, inbuf[1].cbBuffer);
BACKEND->encdata_offset = inbuf[1].cbBuffer; backend->encdata_offset = inbuf[1].cbBuffer;
if(sspi_status == SEC_I_CONTINUE_NEEDED) { if(sspi_status == SEC_I_CONTINUE_NEEDED) {
doread = FALSE; doread = FALSE;
continue; continue;
@ -1257,7 +1258,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
} }
} }
else { else {
BACKEND->encdata_offset = 0; backend->encdata_offset = 0;
} }
break; break;
} }
@ -1284,7 +1285,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
} }
#ifdef HAS_MANUAL_VERIFY_API #ifdef HAS_MANUAL_VERIFY_API
if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) { if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) {
return Curl_verify_certificate(data, conn, sockindex); return Curl_verify_certificate(data, conn, sockindex);
} }
#endif #endif
@ -1366,6 +1367,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN #ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result; SecPkgContext_ApplicationProtocol alpn_result;
#endif #endif
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@ -1373,28 +1375,28 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
"schannel: SSL/TLS connection with %s port %hu (step 3/3)", "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
hostname, conn->remote_port)); hostname, conn->remote_port));
if(!BACKEND->cred) if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
/* check if the required context attributes are met */ /* check if the required context attributes are met */
if(BACKEND->ret_flags != BACKEND->req_flags) { if(backend->ret_flags != backend->req_flags) {
if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT)) if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
failf(data, "schannel: failed to setup sequence detection"); failf(data, "schannel: failed to setup sequence detection");
if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT)) if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
failf(data, "schannel: failed to setup replay detection"); failf(data, "schannel: failed to setup replay detection");
if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY)) if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
failf(data, "schannel: failed to setup confidentiality"); failf(data, "schannel: failed to setup confidentiality");
if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY)) if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
failf(data, "schannel: failed to setup memory allocation"); failf(data, "schannel: failed to setup memory allocation");
if(!(BACKEND->ret_flags & ISC_RET_STREAM)) if(!(backend->ret_flags & ISC_RET_STREAM))
failf(data, "schannel: failed to setup stream orientation"); failf(data, "schannel: failed to setup stream orientation");
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
} }
#ifdef HAS_ALPN #ifdef HAS_ALPN
if(BACKEND->use_alpn) { if(backend->use_alpn) {
sspi_status = sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_APPLICATION_PROTOCOL, SECPKG_ATTR_APPLICATION_PROTOCOL,
&alpn_result); &alpn_result);
@ -1439,7 +1441,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred, incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
NULL, sockindex)); NULL, sockindex));
if(incache) { if(incache) {
if(old_cred != BACKEND->cred) { if(old_cred != backend->cred) {
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: old credential handle is stale, removing")); "schannel: old credential handle is stale, removing"));
/* we're not taking old_cred ownership here, no refcount++ is needed */ /* we're not taking old_cred ownership here, no refcount++ is needed */
@ -1448,7 +1450,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
} }
} }
if(!incache) { if(!incache) {
result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred, result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred,
sizeof(struct Curl_schannel_cred), sizeof(struct Curl_schannel_cred),
sockindex, &added); sockindex, &added);
if(result) { if(result) {
@ -1458,7 +1460,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
} }
else if(added) { else if(added) {
/* this cred session is now also referenced by sessionid cache */ /* this cred session is now also referenced by sessionid cache */
BACKEND->cred->refcount++; backend->cred->refcount++;
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: stored credential handle in session cache")); "schannel: stored credential handle in session cache"));
} }
@ -1469,7 +1471,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
if(data->set.ssl.certinfo) { if(data->set.ssl.certinfo) {
int certs_count = 0; int certs_count = 0;
sspi_status = sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT, SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&ccert_context); &ccert_context);
@ -1606,7 +1608,10 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
* binding to pass the IIS extended protection checks. * binding to pass the IIS extended protection checks.
* Available on Windows 7 or later. * Available on Windows 7 or later.
*/ */
conn->sslContext = &BACKEND->ctxt->ctxt_handle; {
struct ssl_backend_data *backend = connssl->backend;
conn->sslContext = &backend->ctxt->ctxt_handle;
}
#endif #endif
*done = TRUE; *done = TRUE;
@ -1633,13 +1638,14 @@ schannel_send(struct Curl_easy *data, int sockindex,
SecBufferDesc outbuf_desc; SecBufferDesc outbuf_desc;
SECURITY_STATUS sspi_status = SEC_E_OK; SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result; CURLcode result;
struct ssl_backend_data *backend = connssl->backend;
/* check if the maximum stream sizes were queried */ /* check if the maximum stream sizes were queried */
if(BACKEND->stream_sizes.cbMaximumMessage == 0) { if(backend->stream_sizes.cbMaximumMessage == 0) {
sspi_status = s_pSecFn->QueryContextAttributes( sspi_status = s_pSecFn->QueryContextAttributes(
&BACKEND->ctxt->ctxt_handle, &backend->ctxt->ctxt_handle,
SECPKG_ATTR_STREAM_SIZES, SECPKG_ATTR_STREAM_SIZES,
&BACKEND->stream_sizes); &backend->stream_sizes);
if(sspi_status != SEC_E_OK) { if(sspi_status != SEC_E_OK) {
*err = CURLE_SEND_ERROR; *err = CURLE_SEND_ERROR;
return -1; return -1;
@ -1647,13 +1653,13 @@ schannel_send(struct Curl_easy *data, int sockindex,
} }
/* check if the buffer is longer than the maximum message length */ /* check if the buffer is longer than the maximum message length */
if(len > BACKEND->stream_sizes.cbMaximumMessage) { if(len > backend->stream_sizes.cbMaximumMessage) {
len = BACKEND->stream_sizes.cbMaximumMessage; len = backend->stream_sizes.cbMaximumMessage;
} }
/* calculate the complete message length and allocate a buffer for it */ /* calculate the complete message length and allocate a buffer for it */
data_len = BACKEND->stream_sizes.cbHeader + len + data_len = backend->stream_sizes.cbHeader + len +
BACKEND->stream_sizes.cbTrailer; backend->stream_sizes.cbTrailer;
ptr = (unsigned char *) malloc(data_len); ptr = (unsigned char *) malloc(data_len);
if(!ptr) { if(!ptr) {
*err = CURLE_OUT_OF_MEMORY; *err = CURLE_OUT_OF_MEMORY;
@ -1662,12 +1668,12 @@ schannel_send(struct Curl_easy *data, int sockindex,
/* setup output buffers (header, data, trailer, empty) */ /* setup output buffers (header, data, trailer, empty) */
InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER, InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
ptr, BACKEND->stream_sizes.cbHeader); ptr, backend->stream_sizes.cbHeader);
InitSecBuffer(&outbuf[1], SECBUFFER_DATA, InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
ptr + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len)); ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
ptr + BACKEND->stream_sizes.cbHeader + len, ptr + backend->stream_sizes.cbHeader + len,
BACKEND->stream_sizes.cbTrailer); backend->stream_sizes.cbTrailer);
InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, outbuf, 4); InitSecBufferDesc(&outbuf_desc, outbuf, 4);
@ -1675,7 +1681,7 @@ schannel_send(struct Curl_easy *data, int sockindex,
memcpy(outbuf[1].pvBuffer, buf, len); memcpy(outbuf[1].pvBuffer, buf, len);
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0, sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
&outbuf_desc, 0); &outbuf_desc, 0);
/* check if the message was encrypted */ /* check if the message was encrypted */
@ -1780,9 +1786,10 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* we want the length of the encrypted buffer to be at least large enough /* we want the length of the encrypted buffer to be at least large enough
that it can hold all the bytes requested and some TLS record overhead. */ that it can hold all the bytes requested and some TLS record overhead. */
size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
struct ssl_backend_data *backend = connssl->backend;
/**************************************************************************** /****************************************************************************
* Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup. * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
* The pattern for return error is set *err, optional infof, goto cleanup. * The pattern for return error is set *err, optional infof, goto cleanup.
* *
* Our priority is to always return as much decrypted data to the caller as * Our priority is to always return as much decrypted data to the caller as
@ -1794,16 +1801,16 @@ schannel_recv(struct Curl_easy *data, int sockindex,
DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len)); DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
*err = CURLE_OK; *err = CURLE_OK;
if(len && len <= BACKEND->decdata_offset) { if(len && len <= backend->decdata_offset) {
infof(data, "schannel: enough decrypted data is already available"); infof(data, "schannel: enough decrypted data is already available");
goto cleanup; goto cleanup;
} }
else if(BACKEND->recv_unrecoverable_err) { else if(backend->recv_unrecoverable_err) {
*err = BACKEND->recv_unrecoverable_err; *err = backend->recv_unrecoverable_err;
infof(data, "schannel: an unrecoverable error occurred in a prior call"); infof(data, "schannel: an unrecoverable error occurred in a prior call");
goto cleanup; goto cleanup;
} }
else if(BACKEND->recv_sspi_close_notify) { else if(backend->recv_sspi_close_notify) {
/* once a server has indicated shutdown there is no more encrypted data */ /* once a server has indicated shutdown there is no more encrypted data */
infof(data, "schannel: server indicated shutdown in a prior call"); infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup; goto cleanup;
@ -1813,17 +1820,17 @@ schannel_recv(struct Curl_easy *data, int sockindex,
immediately because there may be data to decrypt (in the case we want to immediately because there may be data to decrypt (in the case we want to
decrypt all encrypted cached data) so handle !len later in cleanup. decrypt all encrypted cached data) so handle !len later in cleanup.
*/ */
else if(len && !BACKEND->recv_connection_closed) { else if(len && !backend->recv_connection_closed) {
/* increase enc buffer in order to fit the requested amount of data */ /* increase enc buffer in order to fit the requested amount of data */
size = BACKEND->encdata_length - BACKEND->encdata_offset; size = backend->encdata_length - backend->encdata_offset;
if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
BACKEND->encdata_length < min_encdata_length) { backend->encdata_length < min_encdata_length) {
reallocated_length = BACKEND->encdata_offset + reallocated_length = backend->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE; CURL_SCHANNEL_BUFFER_FREE_SIZE;
if(reallocated_length < min_encdata_length) { if(reallocated_length < min_encdata_length) {
reallocated_length = min_encdata_length; reallocated_length = min_encdata_length;
} }
reallocated_buffer = realloc(BACKEND->encdata_buffer, reallocated_buffer = realloc(backend->encdata_buffer,
reallocated_length); reallocated_length);
if(!reallocated_buffer) { if(!reallocated_buffer) {
*err = CURLE_OUT_OF_MEMORY; *err = CURLE_OUT_OF_MEMORY;
@ -1831,21 +1838,21 @@ schannel_recv(struct Curl_easy *data, int sockindex,
goto cleanup; goto cleanup;
} }
BACKEND->encdata_buffer = reallocated_buffer; backend->encdata_buffer = reallocated_buffer;
BACKEND->encdata_length = reallocated_length; backend->encdata_length = reallocated_length;
size = BACKEND->encdata_length - BACKEND->encdata_offset; size = backend->encdata_length - backend->encdata_offset;
DEBUGF(infof(data, "schannel: encdata_buffer resized %zu", DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
BACKEND->encdata_length)); backend->encdata_length));
} }
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu", "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length)); backend->encdata_offset, backend->encdata_length));
/* read encrypted data from socket */ /* read encrypted data from socket */
*err = Curl_read_plain(conn->sock[sockindex], *err = Curl_read_plain(conn->sock[sockindex],
(char *)(BACKEND->encdata_buffer + (char *)(backend->encdata_buffer +
BACKEND->encdata_offset), backend->encdata_offset),
size, &nread); size, &nread);
if(*err) { if(*err) {
nread = -1; nread = -1;
@ -1858,27 +1865,27 @@ schannel_recv(struct Curl_easy *data, int sockindex,
infof(data, "schannel: Curl_read_plain returned error %d", *err); infof(data, "schannel: Curl_read_plain returned error %d", *err);
} }
else if(nread == 0) { else if(nread == 0) {
BACKEND->recv_connection_closed = true; backend->recv_connection_closed = true;
DEBUGF(infof(data, "schannel: server closed the connection")); DEBUGF(infof(data, "schannel: server closed the connection"));
} }
else if(nread > 0) { else if(nread > 0) {
BACKEND->encdata_offset += (size_t)nread; backend->encdata_offset += (size_t)nread;
BACKEND->encdata_is_incomplete = false; backend->encdata_is_incomplete = false;
DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
} }
} }
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu", "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length)); backend->encdata_offset, backend->encdata_length));
/* decrypt loop */ /* decrypt loop */
while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK && while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
(!len || BACKEND->decdata_offset < len || (!len || backend->decdata_offset < len ||
BACKEND->recv_connection_closed)) { backend->recv_connection_closed)) {
/* prepare data buffer for DecryptMessage call */ /* prepare data buffer for DecryptMessage call */
InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer, InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
curlx_uztoul(BACKEND->encdata_offset)); curlx_uztoul(backend->encdata_offset));
/* we need 3 more empty input buffers for possible output */ /* we need 3 more empty input buffers for possible output */
InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
@ -1888,7 +1895,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
*/ */
sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle, sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
&inbuf_desc, 0, NULL); &inbuf_desc, 0, NULL);
/* check if everything went fine (server may want to renegotiate /* check if everything went fine (server may want to renegotiate
@ -1904,37 +1911,37 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* increase buffer in order to fit the received amount of data */ /* increase buffer in order to fit the received amount of data */
size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
if(BACKEND->decdata_length - BACKEND->decdata_offset < size || if(backend->decdata_length - backend->decdata_offset < size ||
BACKEND->decdata_length < len) { backend->decdata_length < len) {
/* increase internal decrypted data buffer */ /* increase internal decrypted data buffer */
reallocated_length = BACKEND->decdata_offset + size; reallocated_length = backend->decdata_offset + size;
/* make sure that the requested amount of data fits */ /* make sure that the requested amount of data fits */
if(reallocated_length < len) { if(reallocated_length < len) {
reallocated_length = len; reallocated_length = len;
} }
reallocated_buffer = realloc(BACKEND->decdata_buffer, reallocated_buffer = realloc(backend->decdata_buffer,
reallocated_length); reallocated_length);
if(!reallocated_buffer) { if(!reallocated_buffer) {
*err = CURLE_OUT_OF_MEMORY; *err = CURLE_OUT_OF_MEMORY;
failf(data, "schannel: unable to re-allocate memory"); failf(data, "schannel: unable to re-allocate memory");
goto cleanup; goto cleanup;
} }
BACKEND->decdata_buffer = reallocated_buffer; backend->decdata_buffer = reallocated_buffer;
BACKEND->decdata_length = reallocated_length; backend->decdata_length = reallocated_length;
} }
/* copy decrypted data to internal buffer */ /* copy decrypted data to internal buffer */
size = inbuf[1].cbBuffer; size = inbuf[1].cbBuffer;
if(size) { if(size) {
memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset, memcpy(backend->decdata_buffer + backend->decdata_offset,
inbuf[1].pvBuffer, size); inbuf[1].pvBuffer, size);
BACKEND->decdata_offset += size; backend->decdata_offset += size;
} }
DEBUGF(infof(data, "schannel: decrypted data added: %zu", size)); DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: decrypted cached: offset %zu length %zu", "schannel: decrypted cached: offset %zu length %zu",
BACKEND->decdata_offset, BACKEND->decdata_length)); backend->decdata_offset, backend->decdata_length));
} }
/* check for remaining encrypted data */ /* check for remaining encrypted data */
@ -1945,22 +1952,22 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* check if the remaining data is less than the total amount /* check if the remaining data is less than the total amount
* and therefore begins after the already processed data * and therefore begins after the already processed data
*/ */
if(BACKEND->encdata_offset > inbuf[3].cbBuffer) { if(backend->encdata_offset > inbuf[3].cbBuffer) {
/* move remaining encrypted data forward to the beginning of /* move remaining encrypted data forward to the beginning of
buffer */ buffer */
memmove(BACKEND->encdata_buffer, memmove(backend->encdata_buffer,
(BACKEND->encdata_buffer + BACKEND->encdata_offset) - (backend->encdata_buffer + backend->encdata_offset) -
inbuf[3].cbBuffer, inbuf[3].cbBuffer); inbuf[3].cbBuffer, inbuf[3].cbBuffer);
BACKEND->encdata_offset = inbuf[3].cbBuffer; backend->encdata_offset = inbuf[3].cbBuffer;
} }
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: encrypted cached: offset %zu length %zu", "schannel: encrypted cached: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length)); backend->encdata_offset, backend->encdata_length));
} }
else { else {
/* reset encrypted buffer offset, because there is no data remaining */ /* reset encrypted buffer offset, because there is no data remaining */
BACKEND->encdata_offset = 0; backend->encdata_offset = 0;
} }
/* check if server wants to renegotiate the connection context */ /* check if server wants to renegotiate the connection context */
@ -1970,7 +1977,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
infof(data, "schannel: can't renegotiate, an error is pending"); infof(data, "schannel: can't renegotiate, an error is pending");
goto cleanup; goto cleanup;
} }
if(BACKEND->encdata_offset) { if(backend->encdata_offset) {
*err = CURLE_RECV_ERROR; *err = CURLE_RECV_ERROR;
infof(data, "schannel: can't renegotiate, " infof(data, "schannel: can't renegotiate, "
"encrypted data available"); "encrypted data available");
@ -1994,16 +2001,16 @@ schannel_recv(struct Curl_easy *data, int sockindex,
else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
/* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
returned so we have to work around that in cleanup. */ returned so we have to work around that in cleanup. */
BACKEND->recv_sspi_close_notify = true; backend->recv_sspi_close_notify = true;
if(!BACKEND->recv_connection_closed) { if(!backend->recv_connection_closed) {
BACKEND->recv_connection_closed = true; backend->recv_connection_closed = true;
infof(data, "schannel: server closed the connection"); infof(data, "schannel: server closed the connection");
} }
goto cleanup; goto cleanup;
} }
} }
else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
BACKEND->encdata_is_incomplete = true; backend->encdata_is_incomplete = true;
if(!*err) if(!*err)
*err = CURLE_AGAIN; *err = CURLE_AGAIN;
infof(data, "schannel: failed to decrypt data, need more data"); infof(data, "schannel: failed to decrypt data, need more data");
@ -2022,11 +2029,11 @@ schannel_recv(struct Curl_easy *data, int sockindex,
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu", "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length)); backend->encdata_offset, backend->encdata_length));
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: decrypted data buffer: offset %zu length %zu", "schannel: decrypted data buffer: offset %zu length %zu",
BACKEND->decdata_offset, BACKEND->decdata_length)); backend->decdata_offset, backend->decdata_length));
cleanup: cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */ /* Warning- there is no guarantee the encdata state is valid at this point */
@ -2043,13 +2050,13 @@ schannel_recv(struct Curl_easy *data, int sockindex,
assume it was graceful (close_notify) since there doesn't seem to be a assume it was graceful (close_notify) since there doesn't seem to be a
way to tell. way to tell.
*/ */
if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed && if(len && !backend->decdata_offset && backend->recv_connection_closed &&
!BACKEND->recv_sspi_close_notify) { !backend->recv_sspi_close_notify) {
bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT, bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
VERSION_EQUAL); VERSION_EQUAL);
if(isWin2k && sspi_status == SEC_E_OK) if(isWin2k && sspi_status == SEC_E_OK)
BACKEND->recv_sspi_close_notify = true; backend->recv_sspi_close_notify = true;
else { else {
*err = CURLE_RECV_ERROR; *err = CURLE_RECV_ERROR;
infof(data, "schannel: server closed abruptly (missing close_notify)"); infof(data, "schannel: server closed abruptly (missing close_notify)");
@ -2058,23 +2065,23 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* Any error other than CURLE_AGAIN is an unrecoverable error. */ /* Any error other than CURLE_AGAIN is an unrecoverable error. */
if(*err && *err != CURLE_AGAIN) if(*err && *err != CURLE_AGAIN)
BACKEND->recv_unrecoverable_err = *err; backend->recv_unrecoverable_err = *err;
size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset; size = len < backend->decdata_offset ? len : backend->decdata_offset;
if(size) { if(size) {
memcpy(buf, BACKEND->decdata_buffer, size); memcpy(buf, backend->decdata_buffer, size);
memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, memmove(backend->decdata_buffer, backend->decdata_buffer + size,
BACKEND->decdata_offset - size); backend->decdata_offset - size);
BACKEND->decdata_offset -= size; backend->decdata_offset -= size;
DEBUGF(infof(data, "schannel: decrypted data returned %zu", size)); DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
DEBUGF(infof(data, DEBUGF(infof(data,
"schannel: decrypted data buffer: offset %zu length %zu", "schannel: decrypted data buffer: offset %zu length %zu",
BACKEND->decdata_offset, BACKEND->decdata_length)); backend->decdata_offset, backend->decdata_length));
*err = CURLE_OK; *err = CURLE_OK;
return (ssize_t)size; return (ssize_t)size;
} }
if(!*err && !BACKEND->recv_connection_closed) if(!*err && !backend->recv_connection_closed)
*err = CURLE_AGAIN; *err = CURLE_AGAIN;
/* It's debatable what to return when !len. We could return whatever error /* It's debatable what to return when !len. We could return whatever error
@ -2113,10 +2120,11 @@ static bool schannel_data_pending(const struct connectdata *conn,
int sockindex) int sockindex)
{ {
const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
if(connssl->use) /* SSL/TLS is in use */ if(connssl->use) /* SSL/TLS is in use */
return (BACKEND->decdata_offset > 0 || return (backend->decdata_offset > 0 ||
(BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete)); (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
else else
return FALSE; return FALSE;
} }
@ -2146,6 +2154,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
*/ */
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
char * const hostname = SSL_HOST_NAME(); char * const hostname = SSL_HOST_NAME();
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(data); DEBUGASSERT(data);
@ -2154,7 +2163,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
hostname, conn->remote_port); hostname, conn->remote_port);
} }
if(connssl->use && BACKEND->cred && BACKEND->ctxt) { if(connssl->use && backend->cred && backend->ctxt) {
SecBufferDesc BuffDesc; SecBufferDesc BuffDesc;
SecBuffer Buffer; SecBuffer Buffer;
SECURITY_STATUS sspi_status; SECURITY_STATUS sspi_status;
@ -2167,7 +2176,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
InitSecBufferDesc(&BuffDesc, &Buffer, 1); InitSecBufferDesc(&BuffDesc, &Buffer, 1);
sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle, sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
&BuffDesc); &BuffDesc);
if(sspi_status != SEC_E_OK) { if(sspi_status != SEC_E_OK) {
@ -2185,18 +2194,18 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
InitSecBufferDesc(&outbuf_desc, &outbuf, 1); InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
sspi_status = s_pSecFn->InitializeSecurityContext( sspi_status = s_pSecFn->InitializeSecurityContext(
&BACKEND->cred->cred_handle, &backend->cred->cred_handle,
&BACKEND->ctxt->ctxt_handle, &backend->ctxt->ctxt_handle,
host_name, host_name,
BACKEND->req_flags, backend->req_flags,
0, 0,
0, 0,
NULL, NULL,
0, 0,
&BACKEND->ctxt->ctxt_handle, &backend->ctxt->ctxt_handle,
&outbuf_desc, &outbuf_desc,
&BACKEND->ret_flags, &backend->ret_flags,
&BACKEND->ctxt->time_stamp); &backend->ctxt->time_stamp);
curlx_unicodefree(host_name); curlx_unicodefree(host_name);
@ -2215,33 +2224,33 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
} }
/* free SSPI Schannel API security context handle */ /* free SSPI Schannel API security context handle */
if(BACKEND->ctxt) { if(backend->ctxt) {
DEBUGF(infof(data, "schannel: clear security context handle")); DEBUGF(infof(data, "schannel: clear security context handle"));
s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
Curl_safefree(BACKEND->ctxt); Curl_safefree(backend->ctxt);
} }
/* free SSPI Schannel API credential handle */ /* free SSPI Schannel API credential handle */
if(BACKEND->cred) { if(backend->cred) {
Curl_ssl_sessionid_lock(data); Curl_ssl_sessionid_lock(data);
schannel_session_free(BACKEND->cred); schannel_session_free(backend->cred);
Curl_ssl_sessionid_unlock(data); Curl_ssl_sessionid_unlock(data);
BACKEND->cred = NULL; backend->cred = NULL;
} }
/* free internal buffer for received encrypted data */ /* free internal buffer for received encrypted data */
if(BACKEND->encdata_buffer != NULL) { if(backend->encdata_buffer != NULL) {
Curl_safefree(BACKEND->encdata_buffer); Curl_safefree(backend->encdata_buffer);
BACKEND->encdata_length = 0; backend->encdata_length = 0;
BACKEND->encdata_offset = 0; backend->encdata_offset = 0;
BACKEND->encdata_is_incomplete = false; backend->encdata_is_incomplete = false;
} }
/* free internal buffer for received decrypted data */ /* free internal buffer for received decrypted data */
if(BACKEND->decdata_buffer != NULL) { if(backend->decdata_buffer != NULL) {
Curl_safefree(BACKEND->decdata_buffer); Curl_safefree(backend->decdata_buffer);
BACKEND->decdata_length = 0; backend->decdata_length = 0;
BACKEND->decdata_offset = 0; backend->decdata_offset = 0;
} }
return CURLE_OK; return CURLE_OK;
@ -2299,6 +2308,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
const char *pinnedpubkey) const char *pinnedpubkey)
{ {
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
CERT_CONTEXT *pCertContextServer = NULL; CERT_CONTEXT *pCertContextServer = NULL;
/* Result is returned to caller */ /* Result is returned to caller */
@ -2316,7 +2326,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
struct Curl_asn1Element *pubkey; struct Curl_asn1Element *pubkey;
sspi_status = sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle, s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT, SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer); &pCertContextServer);
@ -2422,8 +2432,9 @@ static CURLcode schannel_sha256sum(const unsigned char *input,
static void *schannel_get_internals(struct ssl_connect_data *connssl, static void *schannel_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM) CURLINFO info UNUSED_PARAM)
{ {
struct ssl_backend_data *backend = connssl->backend;
(void)info; (void)info;
return &BACKEND->ctxt->ctxt_handle; return &backend->ctxt->ctxt_handle;
} }
const struct Curl_ssl Curl_ssl_schannel = { const struct Curl_ssl Curl_ssl_schannel = {