/*! * @brief Transmit a packet via SSL _and_ destroy it. * @param remote Pointer to the \c Remote instance. * @param packet Pointer to the \c Packet that is to be sent. * @param completion Pointer to the completion routines to process. * @return An indication of the result of processing the transmission request. * @remark This uses an SSL-encrypted TCP channel, and does not imply the use of HTTPS. */ DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion) { CryptoContext* crypto; Tlv requestId; DWORD res; DWORD idx; TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx; lock_acquire(remote->lock); // If the packet does not already have a request identifier, create one for it if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) { DWORD index; CHAR rid[32]; rid[sizeof(rid)-1] = 0; for (index = 0; index < sizeof(rid)-1; index++) { rid[index] = (rand() % 0x5e) + 0x21; } packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid); } do { // If a completion routine was supplied and the packet has a request // identifier, insert the completion routine into the list if ((completion) && (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) == ERROR_SUCCESS)) { packet_add_completion_handler((LPCSTR)requestId.buffer, completion); } // If the endpoint has a cipher established and this is not a plaintext // packet, we encrypt if ((crypto = remote_get_cipher(remote)) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE)) { ULONG origPayloadLength = packet->payloadLength; PUCHAR origPayload = packet->payload; // Encrypt if ((res = crypto->handlers.encrypt(crypto, packet->payload, packet->payloadLength, &packet->payload, &packet->payloadLength)) != ERROR_SUCCESS) { SetLastError(res); break; } // Destroy the original payload as we no longer need it free(origPayload); // Update the header length packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader)); } dprintf("[PACKET] New xor key for sending"); packet->header.xor_key = rand_xor_key(); // before transmission, xor the whole lot, starting with the body xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength); // then the header xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8); // be sure to switch the xor header before writing packet->header.xor_key = htonl(packet->header.xor_key); idx = 0; while (idx < sizeof(packet->header)) { // Transmit the packet's header (length, type) res = SSL_write( ctx->ssl, (LPCSTR)(&packet->header) + idx, sizeof(packet->header) - idx ); if (res <= 0) { dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx); break; } idx += res; } if (res < 0) { break; } idx = 0; while (idx < packet->payloadLength) { // Transmit the packet's payload (length, type) res = SSL_write( ctx->ssl, packet->payload + idx, packet->payloadLength - idx ); if (res < 0) { break; } idx += res; } if (res < 0) { dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx); break; } SetLastError(ERROR_SUCCESS); } while (0); res = GetLastError(); // Destroy the packet packet_destroy(packet); lock_release(remote->lock); return res; }
/* * Transmit and destroy a packet */ DWORD packet_transmit(Remote *remote, Packet *packet, PacketRequestCompletion *completion) { CryptoContext *crypto; Tlv requestId; DWORD res; DWORD idx; #ifdef _UNIX int local_error = -1; #endif // If the packet does not already have a request identifier, create // one for it if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS) { DWORD index; CHAR rid[32]; rid[sizeof(rid) - 1] = 0; for (index = 0; index < sizeof(rid) - 1; index++) rid[index] = (rand() % 0x5e) + 0x21; packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid); } do { // If a completion routine was supplied and the packet has a request // identifier, insert the completion routine into the list if ((completion) && (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) == ERROR_SUCCESS)) packet_add_completion_handler((LPCSTR)requestId.buffer, completion); // If the endpoint has a cipher established and this is not a plaintext // packet, we encrypt if ((crypto = remote_get_cipher(remote)) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE)) { ULONG origPayloadLength = packet->payloadLength; PUCHAR origPayload = packet->payload; // Encrypt if ((res = crypto->handlers.encrypt(crypto, packet->payload, packet->payloadLength, &packet->payload, &packet->payloadLength)) != ERROR_SUCCESS) { SetLastError(res); break; } // Destroy the original payload as we no longer need it free(origPayload); // Update the header length packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader)); } idx = 0; while( idx < sizeof(packet->header)) { // Transmit the packet's header (length, type) res = SSL_write( remote->ssl, (LPCSTR)(&packet->header) + idx, sizeof(packet->header) - idx ); if(res <= 0) { dprintf("transmit header failed with return %d at index %d\n", res, idx); break; } idx += res; } if(res < 0) break; idx = 0; while( idx < packet->payloadLength) { // Transmit the packet's payload (length, type) res = SSL_write( remote->ssl, packet->payload + idx, packet->payloadLength - idx ); if(res < 0) break; idx += res; } if(res < 0) { dprintf("transmit header failed with return %d at index %d\n", res, idx); break; } SetLastError(ERROR_SUCCESS); } while (0); res = GetLastError(); // Destroy the packet packet_destroy(packet); return res; }
/* * Transmit and destroy a packet over HTTP(S) */ DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion) { CryptoContext *crypto; Tlv requestId; DWORD res; #ifdef _UNIX int local_error = -1; #endif lock_acquire( remote->lock ); // If the packet does not already have a request identifier, create one for it if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,&requestId) != ERROR_SUCCESS) { DWORD index; CHAR rid[32]; rid[sizeof(rid) - 1] = 0; for (index = 0; index < sizeof(rid) - 1; index++) rid[index] = (rand() % 0x5e) + 0x21; packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid); } do { // If a completion routine was supplied and the packet has a request // identifier, insert the completion routine into the list if ((completion) && (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) == ERROR_SUCCESS)) packet_add_completion_handler((LPCSTR)requestId.buffer, completion); // If the endpoint has a cipher established and this is not a plaintext // packet, we encrypt if ((crypto = remote_get_cipher(remote)) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) && (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE)) { ULONG origPayloadLength = packet->payloadLength; PUCHAR origPayload = packet->payload; // Encrypt if ((res = crypto->handlers.encrypt(crypto, packet->payload, packet->payloadLength, &packet->payload, &packet->payloadLength)) != ERROR_SUCCESS) { SetLastError(res); break; } // Destroy the original payload as we no longer need it free(origPayload); // Update the header length packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader)); } #ifdef _WIN32 dprintf("Transmitting packet of length %d to remote", packet->payloadLength); res = packet_transmit_via_http_wininet(remote, packet, completion); #else // XXX: Implement non-windows HTTP delivery #endif if(res < 0) { dprintf("[PACKET] transmit failed with return %d\n", res); break; } SetLastError(ERROR_SUCCESS); } while (0); res = GetLastError(); // Destroy the packet packet_destroy(packet); lock_release( remote->lock ); return res; }