static void on_underlying_io_error(void* context) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; switch (tls_io_instance->tlsio_state) { default: case TLSIO_STATE_NOT_OPEN: case TLSIO_STATE_ERROR: break; case TLSIO_STATE_OPENING_UNDERLYING_IO: case TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT: case TLSIO_STATE_HANDSHAKE_SERVER_HELLO_RECEIVED: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } break; case TLSIO_STATE_CLOSING: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_close_complete != NULL) { tls_io_instance->on_io_close_complete(tls_io_instance->on_io_close_complete_context); } break; case TLSIO_STATE_OPEN: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); break; } }
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; unsigned char* new_socket_io_read_bytes = (unsigned char*)realloc(tls_io_instance->socket_io_read_bytes, tls_io_instance->socket_io_read_byte_count + size); if (new_socket_io_read_bytes == NULL) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->socket_io_read_bytes = new_socket_io_read_bytes; (void)memcpy(tls_io_instance->socket_io_read_bytes + tls_io_instance->socket_io_read_byte_count, buffer, size); tls_io_instance->socket_io_read_byte_count += size; } }
static int on_io_send(WOLFSSL *ssl, char *buf, int sz, void *context) { int result; TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; if (xio_send(tls_io_instance->socket_io, buf, sz, tls_io_instance->on_send_complete, tls_io_instance->on_send_complete_callback_context) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); result = 0; } else { result = sz; } return result; }
static void on_underlying_io_error(void* context) { SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context; switch (sasl_client_io_instance->io_state) { default: break; case IO_STATE_OPENING_UNDERLYING_IO: case IO_STATE_SASL_HANDSHAKE: sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN; indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR); break; case IO_STATE_OPEN: sasl_client_io_instance->io_state = IO_STATE_ERROR; indicate_error(sasl_client_io_instance); break; } }
static void on_underlying_io_error(void* context) { HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context; switch (header_detect_io_instance->io_state) { default: break; case IO_STATE_WAIT_FOR_HEADER: case IO_STATE_OPENING_UNDERLYING_IO: header_detect_io_instance->io_state = IO_STATE_NOT_OPEN; indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR); break; case IO_STATE_OPEN: header_detect_io_instance->io_state = IO_STATE_ERROR; indicate_error(header_detect_io_instance); break; } }
static void on_underlying_io_error(void* context) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; switch (tls_io_instance->tlsio_state) { default: case TLSIO_STATE_NOT_OPEN: case TLSIO_STATE_ERROR: break; case TLSIO_STATE_OPENING_UNDERLYING_IO: case TLSIO_STATE_IN_HANDSHAKE: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_open_complete(tls_io_instance, IO_OPEN_ERROR); break; case TLSIO_STATE_OPEN: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); break; } }
static void handle_error(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance) { switch (sasl_client_io_instance->io_state) { default: case IO_STATE_NOT_OPEN: break; case IO_STATE_OPENING_UNDERLYING_IO: case IO_STATE_SASL_HANDSHAKE: if (xio_close(sasl_client_io_instance->underlying_io, on_underlying_io_close_complete, sasl_client_io_instance) != 0) { sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN; indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR); } break; case IO_STATE_OPEN: sasl_client_io_instance->io_state = IO_STATE_ERROR; indicate_error(sasl_client_io_instance); break; } }
static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT io_open_result) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; if (tls_io_instance->tlsio_state != TLS_SERVER_IO_STATE_OPENING_UNDERLYING_IO) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; indicate_error(tls_io_instance); } else { if (io_open_result != IO_OPEN_OK) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_NOT_OPEN; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { SECURITY_STATUS status; SCHANNEL_CRED auth_data; PCCERT_CONTEXT certContext; auth_data.dwVersion = SCHANNEL_CRED_VERSION; if (tls_io_instance->x509_schannel_handle != NULL) { certContext = x509_schannel_get_certificate_context(tls_io_instance->x509_schannel_handle); auth_data.cCreds = 1; auth_data.paCred = &certContext; } else { certContext = tls_io_instance->cert_context; auth_data.cCreds = 1; auth_data.paCred = &certContext; } auth_data.hRootStore = NULL; auth_data.cSupportedAlgs = 0; auth_data.palgSupportedAlgs = NULL; #if defined(SP_PROT_TLS1_2_SERVER) auth_data.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER; #else auth_data.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; #endif auth_data.dwMinimumCipherStrength = 0; auth_data.dwMaximumCipherStrength = 0; auth_data.dwSessionLifespan = 0; auth_data.dwFlags = SCH_CRED_NO_SYSTEM_MAPPER; auth_data.dwCredFormat = 0; status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_INBOUND, NULL, &auth_data, NULL, NULL, &tls_io_instance->credential_handle, NULL); if (status != SEC_E_OK) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->credential_handle_allocated = true; tls_io_instance->needed_bytes = 1; tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_WAITING_FOR_CLIENT_HELLO; } } } }
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; size_t consumed_bytes; LOG(tls_io_instance->logger_log, LOG_LINE, "%d received on tls_schannel", size); if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0) { memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size); tls_io_instance->received_byte_count += size; if (size > tls_io_instance->needed_bytes) { tls_io_instance->needed_bytes = 0; } else { tls_io_instance->needed_bytes -= size; } /* Drain what we received */ while (tls_io_instance->needed_bytes == 0) { if (tls_io_instance->tlsio_state == TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT) { SecBuffer input_buffers[2]; SecBuffer output_buffers[2]; ULONG context_attributes; /* we need to try and perform the second (next) step of the init */ input_buffers[0].cbBuffer = tls_io_instance->received_byte_count; input_buffers[0].BufferType = SECBUFFER_TOKEN; input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes; input_buffers[1].cbBuffer = 0; input_buffers[1].BufferType = SECBUFFER_EMPTY; input_buffers[1].pvBuffer = 0; SecBufferDesc input_buffers_desc; input_buffers_desc.cBuffers = 2; input_buffers_desc.pBuffers = input_buffers; input_buffers_desc.ulVersion = SECBUFFER_VERSION; output_buffers[0].cbBuffer = 0; output_buffers[0].BufferType = SECBUFFER_TOKEN; output_buffers[0].pvBuffer = NULL; output_buffers[1].cbBuffer = 0; output_buffers[1].BufferType = SECBUFFER_EMPTY; output_buffers[1].pvBuffer = 0; SecBufferDesc output_buffers_desc; output_buffers_desc.cBuffers = 2; output_buffers_desc.pBuffers = output_buffers; output_buffers_desc.ulVersion = SECBUFFER_VERSION; unsigned long flags = ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS; SECURITY_STATUS status = InitializeSecurityContext(&tls_io_instance->credential_handle, &tls_io_instance->security_context, (SEC_CHAR*)tls_io_instance->host_name, flags, 0, 0, &input_buffers_desc, 0, &tls_io_instance->security_context, &output_buffers_desc, &context_attributes, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (input_buffers[1].BufferType != SECBUFFER_MISSING) { //If SECBUFFER_MISSING not sent, try to read byte by byte. tls_io_instance->needed_bytes = 1; } else { tls_io_instance->needed_bytes = input_buffers[1].cbBuffer; } if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } break; case SEC_E_OK: consumed_bytes = tls_io_instance->received_byte_count; /* Any extra bytes left over or did we fully consume the receive buffer? */ if (input_buffers[1].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= input_buffers[1].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_OPEN; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_OK); } } break; case SEC_I_COMPLETE_NEEDED: case SEC_I_CONTINUE_NEEDED: case SEC_I_COMPLETE_AND_CONTINUE: if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { consumed_bytes = tls_io_instance->received_byte_count; /* Any extra bytes left over or did we fully consume the receive buffer? */ if (input_buffers[1].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= input_buffers[1].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT; } } break; case SEC_E_UNTRUSTED_ROOT: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } break; default: { LPVOID srcText = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)srcText, 0, NULL) > 0) { LogError("[%#x] %s", status, (LPTSTR)srcText); LocalFree(srcText); } else { LogError("[%#x]", status); } tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } break; } } else if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN) { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; security_buffers[0].BufferType = SECBUFFER_DATA; security_buffers[0].pvBuffer = tls_io_instance->received_bytes; security_buffers[0].cbBuffer = tls_io_instance->received_byte_count; security_buffers[1].BufferType = SECBUFFER_EMPTY; security_buffers[2].BufferType = SECBUFFER_EMPTY; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (security_buffers[1].BufferType != SECBUFFER_MISSING) { //If SECBUFFER_MISSING not sent, try to read byte by byte. tls_io_instance->needed_bytes = 1; } else { tls_io_instance->needed_bytes = security_buffers[1].cbBuffer; } if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } break; case SEC_E_OK: if (security_buffers[1].BufferType != SECBUFFER_DATA) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { size_t i; if (tls_io_instance->logger_log) { for (i = 0; i < security_buffers[1].cbBuffer; i++) { LOG(tls_io_instance->logger_log, 0, "-> %02x ", ((unsigned char*)security_buffers[1].pvBuffer)[i]); } LOG(tls_io_instance->logger_log, LOG_LINE, ""); } /* notify of the received data */ if (tls_io_instance->on_bytes_received != NULL) { tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, security_buffers[1].pvBuffer, security_buffers[1].cbBuffer); } consumed_bytes = tls_io_instance->received_byte_count; LOG(tls_io_instance->logger_log, LOG_LINE, "%d consumed", tls_io_instance->received_byte_count); for (i = 0; i < sizeof(security_buffers) / sizeof(security_buffers[0]); i++) { /* Any extra bytes left over or did we fully consume the receive buffer? */ if (security_buffers[i].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= security_buffers[i].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); break; } } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } } break; default: { LPVOID srcText = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)srcText, 0, NULL) > 0) { LogError("[%#x] %s", status, (LPTSTR)srcText); LocalFree(srcText); } else { LogError("[%#x]", status); } tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } break; } } else { /* Received data in error or other state */ break; } } } }
static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT io_open_result) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; if (tls_io_instance->tlsio_state != TLSIO_STATE_OPENING_UNDERLYING_IO) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { SecBuffer init_security_buffers[2]; ULONG context_attributes; SECURITY_STATUS status; SCHANNEL_CRED auth_data; auth_data.dwVersion = SCHANNEL_CRED_VERSION; auth_data.cCreds = 0; auth_data.paCred = NULL; auth_data.hRootStore = NULL; auth_data.cSupportedAlgs = 0; auth_data.palgSupportedAlgs = NULL; auth_data.grbitEnabledProtocols = 0; auth_data.dwMinimumCipherStrength = 0; auth_data.dwMaximumCipherStrength = 0; auth_data.dwSessionLifespan = 0; auth_data.dwFlags = SCH_USE_STRONG_CRYPTO | SCH_CRED_NO_DEFAULT_CREDS; auth_data.dwCredFormat = 0; status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &auth_data, NULL, NULL, &tls_io_instance->credential_handle, NULL); if (status != SEC_E_OK) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->credential_handle_allocated = true; init_security_buffers[0].cbBuffer = 0; init_security_buffers[0].BufferType = SECBUFFER_TOKEN; init_security_buffers[0].pvBuffer = NULL; init_security_buffers[1].cbBuffer = 0; init_security_buffers[1].BufferType = SECBUFFER_EMPTY; init_security_buffers[1].pvBuffer = 0; SecBufferDesc security_buffers_desc; security_buffers_desc.cBuffers = 2; security_buffers_desc.pBuffers = init_security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; status = InitializeSecurityContext(&tls_io_instance->credential_handle, NULL, (SEC_CHAR*)tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, NULL, 0, &tls_io_instance->security_context, &security_buffers_desc, &context_attributes, NULL); if ((status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED) || (status == SEC_I_COMPLETE_AND_CONTINUE)) { if (xio_send(tls_io_instance->socket_io, init_security_buffers[0].pvBuffer, init_security_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { /* set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = 1; if (resize_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT; } } } } } }
void tls_server_io_schannel_destroy(CONCRETE_IO_HANDLE tls_io) { if (tls_io != NULL) { LIST_ITEM_HANDLE first_pending_io; TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; if (tls_io_instance->credential_handle_allocated) { (void)FreeCredentialHandle(&tls_io_instance->credential_handle); tls_io_instance->credential_handle_allocated = false; } if (tls_io_instance->received_bytes != NULL) { free(tls_io_instance->received_bytes); } if (tls_io_instance->x509_schannel_handle != NULL) { x509_schannel_destroy(tls_io_instance->x509_schannel_handle); } if (tls_io_instance->x509certificate != NULL) { free(tls_io_instance->x509certificate); } if (tls_io_instance->x509privatekey != NULL) { free(tls_io_instance->x509privatekey); } xio_destroy(tls_io_instance->socket_io); free(tls_io_instance->host_name); first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_io_list); while (first_pending_io != NULL) { PENDING_SEND* pending_send = (PENDING_SEND*)singlylinkedlist_item_get_value(first_pending_io); if (pending_send == NULL) { LogError("Failure: retrieving socket from list"); indicate_error(tls_io_instance); break; } else { if (pending_send->on_send_complete != NULL) { pending_send->on_send_complete(pending_send->on_send_complete_context, IO_SEND_CANCELLED); } if (singlylinkedlist_remove(tls_io_instance->pending_io_list, first_pending_io) != 0) { LogError("Failure: removing pending IO from list"); } } } if (tls_io_instance->cert_context != NULL) { if (!CertFreeCertificateContext(tls_io_instance->cert_context)) { LogError("Failure freeing certificate context"); } } singlylinkedlist_destroy(tls_io_instance->pending_io_list); free(tls_io); } }
void socketio_dowork(CONCRETE_IO_HANDLE socket_io) { if (socket_io != NULL) { SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; if (socket_io_instance->io_state == IO_STATE_OPEN) { int received = 1; LIST_ITEM_HANDLE first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); while (first_pending_io != NULL) { PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)list_item_get_value(first_pending_io); if (pending_socket_io == NULL) { socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); break; } int send_result = tcpsocketconnection_send(socket_io_instance->tcp_socket_connection, (const char*)pending_socket_io->bytes, pending_socket_io->size); if (send_result != pending_socket_io->size) { if (send_result < 0) { if (send_result < UNABLE_TO_COMPLETE) { // Bad error. Indicate as much. socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); } break; } else { /* send something, wait for the rest */ (void)memmove(pending_socket_io->bytes, pending_socket_io->bytes + send_result, pending_socket_io->size - send_result); } } else { if (pending_socket_io->on_send_complete != NULL) { pending_socket_io->on_send_complete(pending_socket_io->callback_context, IO_SEND_OK); } free(pending_socket_io->bytes); free(pending_socket_io); if (list_remove(socket_io_instance->pending_io_list, first_pending_io) != 0) { socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); } } first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); } while (received > 0) { unsigned char recv_bytes[128]; received = tcpsocketconnection_receive(socket_io_instance->tcp_socket_connection, (char*)recv_bytes, sizeof(recv_bytes)); if (received > 0) { if (socket_io_instance->on_bytes_received != NULL) { /* explictly ignoring here the result of the callback */ (void)socket_io_instance->on_bytes_received(socket_io_instance->on_bytes_received_context, recv_bytes, received); } } } } } }
void socketio_dowork(CONCRETE_IO_HANDLE socket_io) { if (socket_io != NULL) { SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; if (socket_io_instance->io_state == IO_STATE_OPEN) { int received = 1; LIST_ITEM_HANDLE first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); while (first_pending_io != NULL) { PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)list_item_get_value(first_pending_io); if (pending_socket_io == NULL) { socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); LogError("Failure: retrieving socket from list"); break; } int send_result = send(socket_io_instance->socket, pending_socket_io->bytes, pending_socket_io->size, 0); if (send_result != pending_socket_io->size) { if (send_result == INVALID_SOCKET) { free(pending_socket_io->bytes); free(pending_socket_io); (void)list_remove(socket_io_instance->pending_io_list, first_pending_io); LogError("Failure: sending Socket information"); socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); } else { /* simply wait */ (void)memmove(pending_socket_io->bytes, pending_socket_io->bytes + send_result, pending_socket_io->size - send_result); } } else { if (pending_socket_io->on_send_complete != NULL) { pending_socket_io->on_send_complete(pending_socket_io->callback_context, IO_SEND_OK); } free(pending_socket_io->bytes); free(pending_socket_io); if (list_remove(socket_io_instance->pending_io_list, first_pending_io) != 0) { socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); LogError("Failure: unable to remove socket from list"); } } first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); } while (received > 0) { unsigned char* recv_bytes = malloc(RECEIVE_BYTES_VALUE); if (recv_bytes == NULL) { LogError("Socketio_Failure: NULL allocating input buffer."); indicate_error(socket_io_instance); } else { received = recv(socket_io_instance->socket, recv_bytes, RECEIVE_BYTES_VALUE, 0); if (received > 0) { int i; for (i = 0; i < received; i++) { LOG(socket_io_instance->logger_log, 0, "<-%02x ", (unsigned char)recv_bytes[i]); } if (socket_io_instance->on_bytes_received != NULL) { /* explictly ignoring here the result of the callback */ (void)socket_io_instance->on_bytes_received(socket_io_instance->on_bytes_received_context, recv_bytes, received); } } free(recv_bytes); } } } } }
int socketio_send(CONCRETE_IO_HANDLE socket_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; if ((socket_io == NULL) || (buffer == NULL) || (size == 0)) { /* Invalid arguments */ LogError("Invalid argument: send given invalid parameter"); result = __LINE__; } else { SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; if (socket_io_instance->io_state != IO_STATE_OPEN) { LogError("Failure: socket state is not opened."); result = __LINE__; } else { LIST_ITEM_HANDLE first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); if (first_pending_io != NULL) { if (add_pending_io(socket_io_instance, buffer, size, on_send_complete, callback_context) != 0) { LogError("Failure: add_pending_io failed."); result = __LINE__; } else { result = 0; } } else { int send_result = send(socket_io_instance->socket, buffer, size, 0); if (send_result != size) { if (send_result == INVALID_SOCKET) { indicate_error(socket_io_instance); LogError("Failure: sending socket failed."); result = __LINE__; } else { /* queue data */ if (add_pending_io(socket_io_instance, buffer + send_result, size - send_result, on_send_complete, callback_context) != 0) { LogError("Failure: add_pending_io failed."); result = __LINE__; } else { result = 0; } } } else { if (on_send_complete != NULL) { on_send_complete(callback_context, IO_SEND_OK); } size_t i; for (i = 0; i < size; i++) { LOG(socket_io_instance->logger_log, 0, "%02x-> ", ((unsigned char*)buffer)[i]); } LOG(socket_io_instance->logger_log, LOG_LINE, ""); result = 0; } } } } return result; }
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; size_t consumed_bytes; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0) { (void)memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size); tls_io_instance->received_byte_count += size; if (size > tls_io_instance->needed_bytes) { tls_io_instance->needed_bytes = 0; } else { tls_io_instance->needed_bytes -= size; } /* Drain what we received */ while (tls_io_instance->needed_bytes == 0) { if ((tls_io_instance->tlsio_state == TLS_SERVER_IO_STATE_IN_HANDSHAKE) || (tls_io_instance->tlsio_state == TLS_SERVER_IO_STATE_WAITING_FOR_CLIENT_HELLO)) { SecBuffer input_buffers[2]; SecBuffer output_buffers[2]; ULONG context_attributes; SECURITY_STATUS status; SecBufferDesc input_buffers_desc; SecBufferDesc output_buffers_desc; input_buffers[0].cbBuffer = (unsigned long)tls_io_instance->received_byte_count; input_buffers[0].BufferType = SECBUFFER_TOKEN; input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes; input_buffers[1].cbBuffer = 0; input_buffers[1].BufferType = SECBUFFER_EMPTY; input_buffers[1].pvBuffer = 0; input_buffers_desc.cBuffers = 2; input_buffers_desc.pBuffers = input_buffers; input_buffers_desc.ulVersion = SECBUFFER_VERSION; output_buffers[0].cbBuffer = 0; output_buffers[0].BufferType = SECBUFFER_TOKEN; output_buffers[0].pvBuffer = NULL; output_buffers[1].cbBuffer = 0; output_buffers[1].BufferType = SECBUFFER_EMPTY; output_buffers[1].pvBuffer = 0; output_buffers_desc.cBuffers = 2; output_buffers_desc.pBuffers = output_buffers; output_buffers_desc.ulVersion = SECBUFFER_VERSION; status = AcceptSecurityContext(&tls_io_instance->credential_handle, (tls_io_instance->tlsio_state == TLS_SERVER_IO_STATE_WAITING_FOR_CLIENT_HELLO) ? NULL : &tls_io_instance->security_context, &input_buffers_desc, ASC_REQ_ALLOCATE_MEMORY, SECURITY_NETWORK_DREP, (tls_io_instance->tlsio_state == TLS_SERVER_IO_STATE_WAITING_FOR_CLIENT_HELLO) ? &tls_io_instance->security_context : NULL, &output_buffers_desc, &context_attributes, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (input_buffers[1].BufferType != SECBUFFER_MISSING) { //If SECBUFFER_MISSING not sent, try to read byte by byte. tls_io_instance->needed_bytes = 1; } else { tls_io_instance->needed_bytes = input_buffers[1].cbBuffer; } if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } break; case SEC_E_OK: if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { consumed_bytes = tls_io_instance->received_byte_count; /* Any extra bytes left over or did we fully consume the receive buffer? */ if (input_buffers[1].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= input_buffers[1].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_OPEN; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_OK); } } } break; case SEC_I_COMPLETE_NEEDED: case SEC_I_CONTINUE_NEEDED: case SEC_I_COMPLETE_AND_CONTINUE: if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { consumed_bytes = tls_io_instance->received_byte_count; /* Any extra bytes left over or did we fully consume the receive buffer? */ if (input_buffers[1].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= input_buffers[1].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_IN_HANDSHAKE; } } break; default: { LPVOID srcText = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)srcText, 0, NULL) > 0) { LogError("[%#x] %s", status, (LPTSTR)srcText); LocalFree(srcText); } else { LogError("[%#x]", status); } tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } break; } } else if (tls_io_instance->tlsio_state == TLS_SERVER_IO_STATE_OPEN) { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; SECURITY_STATUS status; security_buffers[0].BufferType = SECBUFFER_DATA; security_buffers[0].pvBuffer = tls_io_instance->received_bytes; security_buffers[0].cbBuffer = (unsigned long)tls_io_instance->received_byte_count; security_buffers[1].BufferType = SECBUFFER_EMPTY; security_buffers[2].BufferType = SECBUFFER_EMPTY; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (security_buffers[1].BufferType != SECBUFFER_MISSING) { //If SECBUFFER_MISSING not sent, try to read byte by byte. tls_io_instance->needed_bytes = 1; } else { tls_io_instance->needed_bytes = security_buffers[1].cbBuffer; } if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; indicate_error(tls_io_instance); } break; case SEC_E_OK: if (security_buffers[1].BufferType != SECBUFFER_DATA) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; indicate_error(tls_io_instance); } else { size_t i; /* notify of the received data */ if (tls_io_instance->on_bytes_received != NULL) { tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, (const unsigned char *) security_buffers[1].pvBuffer, security_buffers[1].cbBuffer); } consumed_bytes = tls_io_instance->received_byte_count; for (i = 0; i < sizeof(security_buffers) / sizeof(security_buffers[0]); i++) { /* Any extra bytes left over or did we fully consume the receive buffer? */ if (security_buffers[i].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= security_buffers[i].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); break; } } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; indicate_error(tls_io_instance); } } break; default: { LPVOID srcText = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)srcText, 0, NULL) > 0) { LogError("[%#x] %s", status, (LPTSTR)srcText); LocalFree(srcText); } else { LogError("[%#x]", status); } tls_io_instance->tlsio_state = TLS_SERVER_IO_STATE_ERROR; indicate_error(tls_io_instance); } break; } } else { /* Received data in error or other state */ break; } } } }
void socketio_dowork(CONCRETE_IO_HANDLE socket_io) { int send_result; if (socket_io != NULL) { SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; if (socket_io_instance->io_state == IO_STATE_OPEN) { int received = 1; LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list); while (first_pending_io != NULL) { PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)singlylinkedlist_item_get_value(first_pending_io); if (pending_socket_io == NULL) { LogError("Failure: retrieving socket from list"); indicate_error(socket_io_instance); break; } /* TODO: we need to do more than a cast here to be 100% clean The following bug was filed: [WarnL4] socketio_win32 does not account for already sent bytes and there is a truncation of size from size_t to int */ send_result = send(socket_io_instance->socket, (const char*)pending_socket_io->bytes, (int)pending_socket_io->size, 0); if (send_result != (int)pending_socket_io->size) { int last_error = WSAGetLastError(); if (last_error != WSAEWOULDBLOCK) { free(pending_socket_io->bytes); free(pending_socket_io); (void)singlylinkedlist_remove(socket_io_instance->pending_io_list, first_pending_io); } else { /* try again */ } } else { if (pending_socket_io->on_send_complete != NULL) { pending_socket_io->on_send_complete(pending_socket_io->callback_context, IO_SEND_OK); } free(pending_socket_io->bytes); free(pending_socket_io); if (singlylinkedlist_remove(socket_io_instance->pending_io_list, first_pending_io) != 0) { LogError("Failure: removing socket from list"); indicate_error(socket_io_instance); } } first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list); } while (received > 0) { unsigned char* recv_bytes = malloc(RECEIVE_BYTES_VALUE); if (recv_bytes == NULL) { LogError("Socketio_Failure: NULL allocating input buffer."); indicate_error(socket_io_instance); } else { received = recv(socket_io_instance->socket, (char*)recv_bytes, RECEIVE_BYTES_VALUE, 0); if (received > 0) { if (socket_io_instance->on_bytes_received != NULL) { /* explictly ignoring here the result of the callback */ (void)socket_io_instance->on_bytes_received(socket_io_instance->on_bytes_received_context, recv_bytes, received); } } else { int last_error = WSAGetLastError(); if (last_error != WSAEWOULDBLOCK && last_error != ERROR_SUCCESS) { LogError("Socketio_Failure: Recieving data from endpoint: %d.", last_error); indicate_error(socket_io_instance); } } free(recv_bytes); } } } } }
int socketio_send(CONCRETE_IO_HANDLE socket_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; if ((socket_io == NULL) || (buffer == NULL) || (size == 0)) { /* Invalid arguments */ LogError("Invalid argument: send given invalid parameter"); result = __LINE__; } else { SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; if (socket_io_instance->io_state != IO_STATE_OPEN) { LogError("Failure: socket state is not opened."); result = __LINE__; } else { LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list); if (first_pending_io != NULL) { if (add_pending_io(socket_io_instance, buffer, size, on_send_complete, callback_context) != 0) { LogError("Failure: add_pending_io failed."); result = __LINE__; } else { result = 0; } } else { /* TODO: we need to do more than a cast here to be 100% clean The following bug was filed: [WarnL4] socketio_win32 does not account for already sent bytes and there is a truncation of size from size_t to int */ int send_result = send(socket_io_instance->socket, buffer, (int)size, 0); if (send_result != (int)size) { int last_error = WSAGetLastError(); if (last_error != WSAEWOULDBLOCK) { indicate_error(socket_io_instance); LogError("Failure: sending socket failed %d.", last_error); result = __LINE__; } else { /* queue data */ if (add_pending_io(socket_io_instance, buffer, size, on_send_complete, callback_context) != 0) { LogError("Failure: add_pending_io failed."); result = __LINE__; } else { result = 0; } } } else { if (on_send_complete != NULL) { on_send_complete(callback_context, IO_SEND_OK); } result = 0; } } } } return result; }
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0) { memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size); tls_io_instance->received_byte_count += size; if (size > tls_io_instance->needed_bytes) { tls_io_instance->needed_bytes = 0; } else { tls_io_instance->needed_bytes -= size; } switch (tls_io_instance->tlsio_state) { default: break; case TLSIO_STATE_ERROR: break; case TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT: { if (tls_io_instance->needed_bytes == 0) { SecBuffer input_buffers[2]; SecBuffer output_buffers[2]; ULONG context_attributes; /* we need to try and perform the second (next) step of the init */ input_buffers[0].cbBuffer = tls_io_instance->received_byte_count; input_buffers[0].BufferType = SECBUFFER_TOKEN; input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes; input_buffers[1].cbBuffer = 0; input_buffers[1].BufferType = SECBUFFER_EMPTY; input_buffers[1].pvBuffer = 0; SecBufferDesc input_buffers_desc; input_buffers_desc.cBuffers = 2; input_buffers_desc.pBuffers = input_buffers; input_buffers_desc.ulVersion = SECBUFFER_VERSION; output_buffers[0].cbBuffer = 0; output_buffers[0].BufferType = SECBUFFER_TOKEN; output_buffers[0].pvBuffer = NULL; output_buffers[1].cbBuffer = 0; output_buffers[1].BufferType = SECBUFFER_EMPTY; output_buffers[1].pvBuffer = 0; SecBufferDesc output_buffers_desc; output_buffers_desc.cBuffers = 2; output_buffers_desc.pBuffers = output_buffers; output_buffers_desc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = InitializeSecurityContext(&tls_io_instance->credential_handle, &tls_io_instance->security_context, (SEC_CHAR*)tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, &input_buffers_desc, 0, &tls_io_instance->security_context, &output_buffers_desc, &context_attributes, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (input_buffers[1].BufferType != SECBUFFER_MISSING) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { tls_io_instance->needed_bytes = input_buffers[1].cbBuffer; tls_io_instance->consumed_bytes += tls_io_instance->needed_bytes; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } } break; case SEC_E_OK: memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; tls_io_instance->needed_bytes = 1; tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_OPEN; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_OK); } } break; case SEC_I_COMPLETE_NEEDED: case SEC_I_CONTINUE_NEEDED: case SEC_I_COMPLETE_AND_CONTINUE: if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; /* set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = 1; tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { FreeCredentialHandle(&tls_io_instance->credential_handle); tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT; } } break; } } break; case TLSIO_STATE_OPEN: { if (tls_io_instance->needed_bytes == 0) { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; security_buffers[0].BufferType = SECBUFFER_DATA; security_buffers[0].pvBuffer = tls_io_instance->received_bytes; security_buffers[0].cbBuffer = tls_io_instance->received_byte_count; security_buffers[1].BufferType = SECBUFFER_EMPTY; security_buffers[2].BufferType = SECBUFFER_EMPTY; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (security_buffers[1].BufferType != SECBUFFER_MISSING) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->needed_bytes = security_buffers[1].cbBuffer; tls_io_instance->consumed_bytes += tls_io_instance->needed_bytes; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } } break; case SEC_E_OK: if (security_buffers[1].BufferType != SECBUFFER_DATA) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { size_t i; for (i = 0; i < security_buffers[1].cbBuffer; i++) { LOG(tls_io_instance->logger_log, 0, "<-%02x ", ((unsigned char*)security_buffers[1].pvBuffer)[i]); } /* notify of the received data */ if (tls_io_instance->on_bytes_received != NULL) { tls_io_instance->on_bytes_received(tls_io_instance->open_callback_context, security_buffers[1].pvBuffer, security_buffers[1].cbBuffer); } (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; tls_io_instance->needed_bytes = 1; tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } } break; } } break; } } } } }
void socketio_dowork(CONCRETE_IO_HANDLE socket_io) { if (socket_io != NULL) { SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io; if (socket_io_instance->io_state == IO_STATE_OPEN) { int received = 1; LIST_ITEM_HANDLE first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); while (first_pending_io != NULL) { PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)list_item_get_value(first_pending_io); if (pending_socket_io == NULL) { socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); break; } int send_result = send(socket_io_instance->socket, pending_socket_io->bytes, pending_socket_io->size, 0); if (send_result != pending_socket_io->size) { if (send_result == INVALID_SOCKET) { free(pending_socket_io->bytes); free(pending_socket_io); (void)list_remove(socket_io_instance->pending_io_list, first_pending_io); socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); } else { /* simply wait */ (void)memmove(pending_socket_io->bytes, pending_socket_io->bytes + send_result, pending_socket_io->size - send_result); } } else { if (pending_socket_io->on_send_complete != NULL) { pending_socket_io->on_send_complete(pending_socket_io->callback_context, send_result); } free(pending_socket_io->bytes); free(pending_socket_io); if (list_remove(socket_io_instance->pending_io_list, first_pending_io) != 0) { socket_io_instance->io_state = IO_STATE_ERROR; indicate_error(socket_io_instance); } } first_pending_io = list_get_head_item(socket_io_instance->pending_io_list); } while (received > 0) { unsigned char recv_bytes[1]; received = recv(socket_io_instance->socket, recv_bytes, sizeof(recv_bytes), 0); if (received > 0) { int i; for (i = 0; i < received; i++) { LOG(socket_io_instance->logger_log, 0, "<-%02x ", (unsigned char)recv_bytes[i]); } if (socket_io_instance->on_bytes_received != NULL) { /* explictly ignoring here the result of the callback */ (void)socket_io_instance->on_bytes_received(socket_io_instance->open_callback_context, recv_bytes, received); } } } } } }