int tls_process_segment(packet_t *packet, struct tcphdr *tcp) { struct SSLConnection *conn; const u_char *payload = packet_payload(packet); uint32_t size_payload = packet_payloadlen(packet); uint8_t *out; uint32_t outl = packet->payload_len; out = sng_malloc(outl); struct in_addr ip_src, ip_dst; uint16_t sport = packet->src.port; uint16_t dport = packet->dst.port; // Convert addresses inet_pton(AF_INET, packet->src.ip, &ip_src); inet_pton(AF_INET, packet->dst.ip, &ip_dst); // Try to find a session for this ip if ((conn = tls_connection_find(ip_src, sport))) { // Update last connection direction conn->direction = tls_connection_dir(conn, ip_src, sport); // Check current connection state switch (conn->state) { case TCP_STATE_SYN: // First SYN received, this package must be SYN/ACK if (tcp->th_flags & TH_SYN & ~TH_ACK) conn->state = TCP_STATE_SYN_ACK; break; case TCP_STATE_SYN_ACK: // We expect an ACK packet here if (tcp->th_flags & ~TH_SYN & TH_ACK) conn->state = TCP_STATE_ESTABLISHED; break; case TCP_STATE_ACK: case TCP_STATE_ESTABLISHED: // Process data segment! if (tls_process_record(conn, payload, size_payload, &out, &outl) == 0) { if ((int32_t) outl > 0) { packet_set_payload(packet, out, outl); packet_set_type(packet, PACKET_SIP_TLS); return 0; } } break; case TCP_STATE_FIN: case TCP_STATE_CLOSED: // We can delete this connection tls_connection_destroy(conn); break; } } else { if (tcp->th_flags & TH_SYN & ~TH_ACK) { // New connection, store it status and leave tls_connection_create(ip_src, sport, ip_dst, dport); } } sng_free(out); return 0; }
int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment, const int len) { struct Handshake *handshake; struct ClientHello *clienthello; struct ServerHello *serverhello; struct ClientKeyExchange *clientkeyex; const opaque *body; // Get Handshake data handshake = (struct Handshake *) fragment; if (UINT24_INT(handshake->length) > 0) { // Hanshake body pointer body = fragment + sizeof(struct Handshake); switch (handshake->type) { case hello_request: break; case client_hello: // Store client random clienthello = (struct ClientHello *) body; memcpy(&conn->client_random, &clienthello->random, sizeof(struct Random)); // Check we have a TLS handshake if (!(clienthello->client_version.major == 0x03)) { tls_connection_destroy(conn); return 1; } // Only TLS 1.0, 1.1 or 1.2 connections if (clienthello->client_version.minor != 0x01 && clienthello->client_version.minor != 0x02 && clienthello->client_version.minor != 0x03) { tls_connection_destroy(conn); return 1; } // Store TLS version conn->version = clienthello->client_version.minor; break; case server_hello: // Store server random serverhello = (struct ServerHello *) body; memcpy(&conn->server_random, &serverhello->random, sizeof(struct Random)); // Get the selected cipher memcpy(&conn->cipher_suite, body + sizeof(struct ServerHello) + serverhello->session_id_length, sizeof(uint16_t)); // Check if we have a handled cipher if (tls_connection_load_cipher(conn) != 0) { tls_connection_destroy(conn); return 1; } break; case certificate: case certificate_request: case server_hello_done: case certificate_verify: break; case client_key_exchange: // Decrypt PreMasterKey clientkeyex = (struct ClientKeyExchange *) body; RSA_private_decrypt(UINT16_INT(clientkeyex->length), (const unsigned char *) &clientkeyex->exchange_keys, (unsigned char *) &conn->pre_master_secret, conn->server_private_key->pkey.rsa, RSA_PKCS1_PADDING); tls_debug_print_hex("client_random", &conn->client_random, 32); tls_debug_print_hex("server_random", &conn->server_random, 32); uint8_t *seed = sng_malloc(sizeof(struct Random) * 2); memcpy(seed, &conn->client_random, sizeof(struct Random)); memcpy(seed + sizeof(struct Random), &conn->server_random, sizeof(struct Random)); if (conn->version < 3) { // Get MasterSecret PRF((unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) &conn->pre_master_secret, sizeof(struct PreMasterSecret), (unsigned char *) "master secret", seed, sizeof(struct Random) * 2); } else { PRF12((unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) &conn->pre_master_secret, sizeof(struct PreMasterSecret), (unsigned char *) "master secret", seed, sizeof(struct Random) * 2); } tls_debug_print_hex("master_secret", conn->master_secret.random, 48); memcpy(seed, &conn->server_random, sizeof(struct Random) * 2); memcpy(seed + sizeof(struct Random), &conn->client_random, sizeof(struct Random)); // Generate MACs, Write Keys and IVs if (conn->version < 3) { PRF((unsigned char *) &conn->key_material, sizeof(struct tls_data), (unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) "key expansion", seed, sizeof(struct Random) * 2); } else { PRF12((unsigned char *) &conn->key_material, sizeof(struct tls_data), (unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) "key expansion", seed, sizeof(struct Random) * 2); } tls_debug_print_hex("client_write_MAC_key", conn->key_material.client_write_MAC_key, 20); tls_debug_print_hex("server_write_MAC_key", conn->key_material.server_write_MAC_key, 20); tls_debug_print_hex("client_write_key", conn->key_material.client_write_key, 32); tls_debug_print_hex("server_write_key", conn->key_material.server_write_key, 32); tls_debug_print_hex("client_write_IV", conn->key_material.client_write_IV, 16); tls_debug_print_hex("server_write_IV", conn->key_material.server_write_IV, 16); // Done with the seed sng_free(seed); // Create Client decoder EVP_CIPHER_CTX_init(&conn->client_cipher_ctx); EVP_CipherInit(&conn->client_cipher_ctx, conn->ciph, conn->key_material.client_write_key, conn->key_material.client_write_IV, 0); EVP_CIPHER_CTX_init(&conn->server_cipher_ctx); EVP_CipherInit(&conn->server_cipher_ctx, conn->ciph, conn->key_material.server_write_key, conn->key_material.server_write_IV, 0); break; case new_session_ticket: case finished: break; default: if (conn->encrypted) { // Encrypted Hanshake Message uint8_t *decoded = sng_malloc(len); uint32_t decodedlen = len; tls_process_record_data(conn, fragment, len, &decoded, &decodedlen); sng_free(decoded); } break; } } return 0; }