static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context; while (size > 0) { switch (header_detect_io_instance->io_state) { default: break; case IO_STATE_WAIT_FOR_HEADER: if (amqp_header[header_detect_io_instance->header_pos] != buffer[0]) { /* Send expected header, then close as per spec. We do not care if we fail */ (void)xio_send(header_detect_io_instance->underlying_io, amqp_header, sizeof(amqp_header), on_send_complete_close, context); header_detect_io_instance->io_state = IO_STATE_NOT_OPEN; indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR); size = 0; } else { header_detect_io_instance->header_pos++; size--; buffer++; if (header_detect_io_instance->header_pos == sizeof(amqp_header)) { if (xio_send(header_detect_io_instance->underlying_io, amqp_header, sizeof(amqp_header), NULL, NULL) != 0) { header_detect_io_instance->io_state = IO_STATE_NOT_OPEN; indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR); } else { header_detect_io_instance->io_state = IO_STATE_OPEN; indicate_open_complete(header_detect_io_instance, IO_OPEN_OK); } } } break; case IO_STATE_OPEN: header_detect_io_instance->on_bytes_received(header_detect_io_instance->on_bytes_received_context, buffer, size); size = 0; break; } } }
int headerdetectio_send(CONCRETE_IO_HANDLE header_detect_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; if (header_detect_io == NULL) { result = __LINE__; } else { HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io; if (header_detect_io_instance->io_state != IO_STATE_OPEN) { result = __LINE__; } else { if (xio_send(header_detect_io_instance->underlying_io, buffer, size, on_send_complete, callback_context) != 0) { result = __LINE__; } else { result = 0; } } } return result; }
static void on_bytes_encoded(void* context, const unsigned char* bytes, size_t length, bool encode_complete) { (void)encode_complete; SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context; /* Codes_SRS_SASLCLIENTIO_01_120: [When SASL client IO is notified by sasl_frame_codec of bytes that have been encoded via the on_bytes_encoded callback and SASL client IO is in the state OPENING, SASL client IO shall send these bytes by using xio_send.] */ if (xio_send(sasl_client_io_instance->underlying_io, bytes, length, NULL, NULL) != 0) { /* Codes_SRS_SASLCLIENTIO_01_121: [If xio_send fails, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */ handle_error(sasl_client_io_instance); } }
int saslclientio_send(CONCRETE_IO_HANDLE sasl_client_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; /* Codes_SRS_SASLCLIENTIO_01_022: [If the saslio or buffer argument is NULL, saslclientio_send shall fail and return a non-zero value.] */ if ((sasl_client_io == NULL) || (buffer == NULL) || /* Codes_SRS_SASLCLIENTIO_01_023: [If size is 0, saslclientio_send shall fail and return a non-zero value.] */ (size == 0)) { /* Invalid arguments */ result = __LINE__; } else { SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io; if (sasl_client_io_instance->logger_log != NULL) { size_t i; for (i = 0; i < size; i++) { LOG(sasl_client_io_instance->logger_log, 0, " %02x", ((const unsigned char*)buffer)[i]); } } /* Codes_SRS_SASLCLIENTIO_01_019: [If saslclientio_send is called while the SASL client IO state is not IO_STATE_OPEN, saslclientio_send shall fail and return a non-zero value.] */ if (sasl_client_io_instance->io_state != IO_STATE_OPEN) { result = __LINE__; } else { /* Codes_SRS_SASLCLIENTIO_01_020: [If the SASL client IO state is IO_STATE_OPEN, saslclientio_send shall call xio_send on the underlying_io passed to saslclientio_create, while passing as arguments the buffer, size, on_send_complete and callback_context.] */ if (xio_send(sasl_client_io_instance->underlying_io, buffer, size, on_send_complete, callback_context) != 0) { /* Codes_SRS_SASLCLIENTIO_01_024: [If the call to xio_send fails, then saslclientio_send shall fail and return a non-zero value.] */ result = __LINE__; } else { /* Codes_SRS_SASLCLIENTIO_01_021: [On success, saslclientio_send shall return 0.] */ result = 0; } } } return result; }
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 int send_sasl_header(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance) { int result; /* Codes_SRS_SASLCLIENTIO_01_078: [SASL client IO shall start the header exchange by sending the SASL header.] */ /* Codes_SRS_SASLCLIENTIO_01_095: [Sending the header shall be done by using xio_send.] */ if (xio_send(sasl_client_io_instance->underlying_io, sasl_header, sizeof(sasl_header), NULL, NULL) != 0) { result = __LINE__; } else { LOG(sasl_client_io_instance->logger_log, LOG_LINE, "-> Header (AMQP 3.1.0.0)"); result = 0; } return result; }
static int send_chunk(CONCRETE_IO_HANDLE tls_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; if ((tls_io == NULL) || (buffer == NULL) || (size == 0)) { /* Invalid arguments */ result = __LINE__; } else { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN) { result = __LINE__; } else { SecPkgContext_StreamSizes sizes; SECURITY_STATUS status = QueryContextAttributes(&tls_io_instance->security_context, SECPKG_ATTR_STREAM_SIZES, &sizes); if (status != SEC_E_OK) { result = __LINE__; } else { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; size_t needed_buffer = sizes.cbHeader + size + sizes.cbTrailer; unsigned char* out_buffer = (unsigned char*)malloc(needed_buffer); if (out_buffer == NULL) { result = __LINE__; } else { memcpy(out_buffer + sizes.cbHeader, buffer, size); security_buffers[0].BufferType = SECBUFFER_STREAM_HEADER; security_buffers[0].cbBuffer = sizes.cbHeader; security_buffers[0].pvBuffer = out_buffer; security_buffers[1].BufferType = SECBUFFER_DATA; security_buffers[1].cbBuffer = size; security_buffers[1].pvBuffer = out_buffer + sizes.cbHeader; security_buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; security_buffers[2].cbBuffer = sizes.cbTrailer; security_buffers[2].pvBuffer = out_buffer + sizes.cbHeader + size; security_buffers[3].cbBuffer = 0; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers[3].pvBuffer = 0; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; status = EncryptMessage(&tls_io_instance->security_context, 0, &security_buffers_desc, 0); if (FAILED(status)) { result = __LINE__; } else { if (xio_send(tls_io_instance->socket_io, out_buffer, security_buffers[0].cbBuffer + security_buffers[1].cbBuffer + security_buffers[2].cbBuffer, on_send_complete, callback_context) != 0) { result = __LINE__; } else { size_t i; for (i = 0; i < size; i++) { LOG(tls_io_instance->logger_log, 0, "%02x-> ", ((unsigned char*)buffer)[i]); } LOG(tls_io_instance->logger_log, LOG_LINE, ""); result = 0; } } free(out_buffer); } } } } 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; 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; } } } } } }
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; } } } } }
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; } } } }
static int send_chunk(CONCRETE_IO_HANDLE tls_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; if ((tls_io == NULL) || (buffer == NULL) || (size == 0)) { LogError("invalid argument detected: CONCRETE_IO_HANDLE tls_io = %p, const void* buffer = %p, size_t size = %d", tls_io, buffer, size); result = __FAILURE__; } else { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; if (tls_io_instance->tlsio_state != TLS_SERVER_IO_STATE_OPEN) { LogError("invalid tls_io_instance->tlsio_state: %s", ENUM_TO_STRING(TLS_SERVER_IO_STATE, tls_io_instance->tlsio_state)); result = __FAILURE__; } else { SecPkgContext_StreamSizes sizes; SECURITY_STATUS status = QueryContextAttributes(&tls_io_instance->security_context, SECPKG_ATTR_STREAM_SIZES, &sizes); if (status != SEC_E_OK) { LogError("QueryContextAttributes failed: %x", status); result = __FAILURE__; } else { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; size_t needed_buffer = sizes.cbHeader + size + sizes.cbTrailer; unsigned char* out_buffer = (unsigned char*)malloc(needed_buffer); if (out_buffer == NULL) { LogError("malloc failed"); result = __FAILURE__; } else { (void)memcpy(out_buffer + sizes.cbHeader, buffer, size); security_buffers[0].BufferType = SECBUFFER_STREAM_HEADER; security_buffers[0].cbBuffer = sizes.cbHeader; security_buffers[0].pvBuffer = out_buffer; security_buffers[1].BufferType = SECBUFFER_DATA; security_buffers[1].cbBuffer = (unsigned long)size; security_buffers[1].pvBuffer = out_buffer + sizes.cbHeader; security_buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; security_buffers[2].cbBuffer = sizes.cbTrailer; security_buffers[2].pvBuffer = out_buffer + sizes.cbHeader + size; security_buffers[3].cbBuffer = 0; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers[3].pvBuffer = 0; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; status = EncryptMessage(&tls_io_instance->security_context, 0, &security_buffers_desc, 0); if (FAILED(status)) { LogError("EncryptMessage failed: %x", status); result = __FAILURE__; } else { if (xio_send(tls_io_instance->socket_io, out_buffer, security_buffers[0].cbBuffer + security_buffers[1].cbBuffer + security_buffers[2].cbBuffer, on_send_complete, callback_context) != 0) { LogError("xio_send failed"); result = __FAILURE__; } else { result = 0; } } free(out_buffer); } } } } return result; }