1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

schannel: Don't treat encrypted partial record as pending data

- Track when the cached encrypted data contains only a partial record
  that can't be decrypted without more data (SEC_E_INCOMPLETE_MESSAGE).

- Change Curl_schannel_data_pending to return false in such a case.

Other SSL libraries have pending data functions that behave similarly.

Ref: https://github.com/curl/curl/pull/1387

Closes https://github.com/curl/curl/pull/1392
This commit is contained in:
Jay Satiro 2017-04-06 03:27:28 -04:00
parent be299a4dba
commit 6b39f9c87e
2 changed files with 15 additions and 2 deletions

View File

@ -333,6 +333,11 @@ struct ssl_connect_data {
size_t encdata_length, decdata_length; size_t encdata_length, decdata_length;
size_t encdata_offset, decdata_offset; size_t encdata_offset, decdata_offset;
unsigned char *encdata_buffer, *decdata_buffer; unsigned char *encdata_buffer, *decdata_buffer;
/* encdata_is_incomplete: if encdata contains only a partial record that
can't be decrypted without another Curl_read_plain (that is, status is
SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
more bytes into encdata then set this back to false. */
bool encdata_is_incomplete;
unsigned long req_flags, ret_flags; unsigned long req_flags, ret_flags;
CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */

View File

@ -432,6 +432,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
connssl->recv_unrecoverable_err = CURLE_OK; connssl->recv_unrecoverable_err = CURLE_OK;
connssl->recv_sspi_close_notify = false; connssl->recv_sspi_close_notify = false;
connssl->recv_connection_closed = false; connssl->recv_connection_closed = false;
connssl->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;
@ -480,6 +481,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* buffer to store previously received and encrypted data */ /* buffer to store previously received and encrypted data */
if(connssl->encdata_buffer == NULL) { if(connssl->encdata_buffer == NULL) {
connssl->encdata_is_incomplete = false;
connssl->encdata_offset = 0; connssl->encdata_offset = 0;
connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
connssl->encdata_buffer = malloc(connssl->encdata_length); connssl->encdata_buffer = malloc(connssl->encdata_length);
@ -532,6 +534,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* increase encrypted data buffer offset */ /* increase encrypted data buffer offset */
connssl->encdata_offset += nread; connssl->encdata_offset += nread;
connssl->encdata_is_incomplete = false;
infof(data, "schannel: encrypted data got %zd\n", nread);
} }
infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
@ -576,6 +580,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* 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) {
connssl->encdata_is_incomplete = true;
connssl->connecting_state = ssl_connect_2_reading; connssl->connecting_state = ssl_connect_2_reading;
infof(data, "schannel: received incomplete message, need more data\n"); infof(data, "schannel: received incomplete message, need more data\n");
return CURLE_OK; return CURLE_OK;
@ -1177,6 +1182,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
} }
else if(nread > 0) { else if(nread > 0) {
connssl->encdata_offset += (size_t)nread; connssl->encdata_offset += (size_t)nread;
connssl->encdata_is_incomplete = false;
infof(data, "schannel: encrypted data got %zd\n", nread); infof(data, "schannel: encrypted data got %zd\n", nread);
} }
} }
@ -1313,6 +1319,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
} }
} }
else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
connssl->encdata_is_incomplete = true;
if(!*err) if(!*err)
*err = CURLE_AGAIN; *err = CURLE_AGAIN;
infof(data, "schannel: failed to decrypt data, need more data\n"); infof(data, "schannel: failed to decrypt data, need more data\n");
@ -1414,8 +1421,8 @@ bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
const struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
if(connssl->use) /* SSL/TLS is in use */ if(connssl->use) /* SSL/TLS is in use */
return (connssl->encdata_offset > 0 || return (connssl->decdata_offset > 0 ||
connssl->decdata_offset > 0) ? TRUE : FALSE; (connssl->encdata_offset > 0 && !connssl->encdata_is_incomplete));
else else
return FALSE; return FALSE;
} }
@ -1518,6 +1525,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
Curl_safefree(connssl->encdata_buffer); Curl_safefree(connssl->encdata_buffer);
connssl->encdata_length = 0; connssl->encdata_length = 0;
connssl->encdata_offset = 0; connssl->encdata_offset = 0;
connssl->encdata_is_incomplete = false;
} }
/* free internal buffer for received decrypted data */ /* free internal buffer for received decrypted data */