int tls_process_record(struct SSLConnection *conn, const uint8_t *payload, const int len, uint8_t **out, uint32_t *outl) { struct TLSPlaintext *record; int record_len; const opaque *fragment; // No record data here! if (len == 0) return 0; // Get Record data record = (struct TLSPlaintext *) payload; record_len = sizeof(struct TLSPlaintext) + UINT16_INT(record->length); // Process record fragment if (UINT16_INT(record->length) > 0) { // TLSPlaintext fragment pointer fragment = (opaque *) payload + sizeof(struct TLSPlaintext); switch (record->type) { case handshake: // Hanshake Record, Try to get MasterSecret data if (tls_process_record_handshake(conn, fragment, UINT16_INT(record->length)) != 0) return 1; break; case change_cipher_spec: // From now on, this connection will be encrypted using MasterSecret conn->encrypted = 1; break; case application_data: if (conn->encrypted) { // Decrypt application data using MasterSecret tls_process_record_data(conn, fragment, UINT16_INT(record->length), out, outl); } break; default: break; } } // MultiRecord packet if (len > record_len) { *outl = len; return tls_process_record(conn, payload + record_len, len - record_len, out, outl); } return 0; }
int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment) { 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 && clienthello->client_version.minor == 0x01)) { tls_connection_destroy(conn); return 1; } 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; gnutls_datum_t exkeys, pms; exkeys.size = UINT16_INT(clientkeyex->length); exkeys.data = (unsigned char *)&clientkeyex->exchange_keys; gnutls_privkey_decrypt_data(conn->server_private_key, 0, &exkeys, &pms); memcpy(&conn->pre_master_secret, pms.data, pms.size); // Get MasterSecret unsigned char *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)); 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); memcpy(seed, &conn->server_random, sizeof(struct Random)); memcpy(seed + sizeof(struct Random), &conn->client_random, sizeof(struct Random)); // Generate MACs, Write Keys and IVs 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); // Done with the seed sng_free(seed); // Create Client decoder gcry_cipher_open(&conn->client_cipher_ctx, conn->ciph, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_setkey(conn->client_cipher_ctx, conn->key_material.client_write_key, gcry_cipher_get_algo_keylen(conn->ciph)); gcry_cipher_setiv(conn->client_cipher_ctx, conn->key_material.client_write_IV, gcry_cipher_get_algo_blklen(conn->ciph)); // Create Server decoder gcry_cipher_open(&conn->server_cipher_ctx, conn->ciph, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_setkey(conn->server_cipher_ctx, conn->key_material.server_write_key, gcry_cipher_get_algo_keylen(conn->ciph)); gcry_cipher_setiv(conn->server_cipher_ctx, conn->key_material.server_write_IV, gcry_cipher_get_algo_blklen(conn->ciph)); break; case finished: break; default: if (conn->encrypted) { // Encrypted Hanshake Message unsigned char *decoded = sng_malloc(48); uint32_t decodedlen; tls_process_record_data(conn, fragment, 48, &decoded, &decodedlen); sng_free(decoded); } break; } } 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; }