/* Apply the TLS PRF using the TLS/IA inner secret as keying material, where the seed is the client random concatenated with the server random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0 respectively). LABEL and LABEL_SIZE is used as the label. The result is placed in pre-allocated OUT of OUTSIZE length. */ static int _gnutls_ia_prf (gnutls_session_t session, size_t label_size, const char *label, size_t extra_size, const char *extra, size_t outsize, opaque * out) { int ret; opaque *seed; size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size; seed = gnutls_malloc (seedsize); if (!seed) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } memcpy (seed, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy (seed + GNUTLS_RANDOM_SIZE, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size); ret = _gnutls_PRF (session, session->security_parameters.inner_secret, GNUTLS_MASTER_SIZE, label, label_size, seed, seedsize, outsize, out); gnutls_free (seed); return ret; }
/** * gnutls_ia_verify_endphase: * @session: is a #gnutls_session_t structure. * @checksum: 12-byte checksum data, received from gnutls_ia_recv(). * * Verify TLS/IA end phase checksum data. If verification fails, the * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other * sie. * * This function is called when gnutls_ia_recv() return * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED. * * Return value: Return 0 on successful verification, or an error * code. If the checksum verification of the end phase message fails, * %GNUTLS_E_IA_VERIFY_FAILED is returned. **/ int gnutls_ia_verify_endphase (gnutls_session_t session, const char *checksum) { char local_checksum[CHECKSUM_SIZE]; int client = session->security_parameters.entity == GNUTLS_CLIENT; const char *label = client ? server_finished_label : client_finished_label; int size_of_label = client ? sizeof (server_finished_label) : sizeof (client_finished_label); int ret; ret = _gnutls_PRF (session, session->security_parameters.inner_secret, GNUTLS_MASTER_SIZE, label, size_of_label - 1, "", 0, CHECKSUM_SIZE, local_checksum); if (ret < 0) { gnutls_assert (); return ret; } if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0) { ret = gnutls_alert_send (session, GNUTLS_AL_FATAL, GNUTLS_A_INNER_APPLICATION_VERIFICATION); if (ret < 0) { gnutls_assert (); return ret; } return GNUTLS_E_IA_VERIFY_FAILED; } return 0; }
/** * gnutls_ia_endphase_send: * @session: is a #gnutls_session_t structure. * @final_p: Set iff this should signal the final phase. * * Send a TLS/IA end phase message. * * In the client, this should only be used to acknowledge an end phase * message sent by the server. * * In the server, this can be called instead of gnutls_ia_send() if * the server wishes to end an application phase. * * Return value: Return 0 on success, or an error code. **/ int gnutls_ia_endphase_send (gnutls_session_t session, int final_p) { opaque local_checksum[CHECKSUM_SIZE]; int client = session->security_parameters.entity == GNUTLS_CLIENT; const char *label = client ? client_finished_label : server_finished_label; int size_of_label = client ? sizeof (client_finished_label) : sizeof (server_finished_label); ssize_t len; int ret; ret = _gnutls_PRF (session, session->security_parameters.inner_secret, GNUTLS_MASTER_SIZE, label, size_of_label - 1, /* XXX specification unclear on seed. */ "", 0, CHECKSUM_SIZE, local_checksum); if (ret < 0) return ret; len = _gnutls_send_inner_application (session, final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED : GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE); /* XXX Instead of calling this function over and over...? * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED) * len = _gnutls_io_write_flush(session); */ if (len < 0) { gnutls_assert (); return len; } return 0; }
/* This function is to be called after handshake, when master_secret, * client_random and server_random have been initialized. * This function creates the keys and stores them into pending session. * (session->cipher_specs) */ static int _gnutls_set_keys (gnutls_session_t session, record_parameters_st * params, int hash_size, int IV_size, int key_size, int export_flag) { /* FIXME: This function is too long */ opaque rnd[2 * GNUTLS_RANDOM_SIZE]; opaque rrnd[2 * GNUTLS_RANDOM_SIZE]; int pos, ret; int block_size; char buf[65]; /* avoid using malloc */ opaque key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE + 2 * MAX_CIPHER_BLOCK_SIZE]; record_state_st *client_write, *server_write; client_write = session->security_parameters.entity == GNUTLS_CLIENT ? ¶ms->write : ¶ms->read; server_write = session->security_parameters.entity == GNUTLS_SERVER ? ¶ms->write : ¶ms->read; block_size = 2 * hash_size + 2 * key_size; if (export_flag == 0) block_size += 2 * IV_size; memcpy (rnd, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy (&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (rrnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (&rrnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_generate_random (session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, keyexp, keyexp_length, rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block); } if (ret < 0) return gnutls_assert_val (ret); _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size, _gnutls_bin2hex (key_block, block_size, buf, sizeof (buf), NULL)); pos = 0; if (hash_size > 0) { if (_gnutls_sset_datum (&client_write->mac_secret, &key_block[pos], hash_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); pos += hash_size; if (_gnutls_sset_datum (&server_write->mac_secret, &key_block[pos], hash_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); pos += hash_size; } if (key_size > 0) { opaque key1[EXPORT_FINAL_KEY_SIZE]; opaque key2[EXPORT_FINAL_KEY_SIZE]; opaque *client_write_key, *server_write_key; int client_write_key_size, server_write_key_size; if (export_flag == 0) { client_write_key = &key_block[pos]; client_write_key_size = key_size; pos += key_size; server_write_key = &key_block[pos]; server_write_key_size = key_size; pos += key_size; } else { /* export */ client_write_key = key1; server_write_key = key2; /* generate the final keys */ if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_hash_md5 (&key_block[pos], key_size, rrnd, 2 * GNUTLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, client_write_key); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, &key_block[pos], key_size, cliwrite, cliwrite_length, rrnd, 2 * GNUTLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, client_write_key); } if (ret < 0) return gnutls_assert_val (ret); client_write_key_size = EXPORT_FINAL_KEY_SIZE; pos += key_size; if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_hash_md5 (&key_block[pos], key_size, rnd, 2 * GNUTLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, server_write_key); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, &key_block[pos], key_size, servwrite, servwrite_length, rrnd, 2 * GNUTLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, server_write_key); } if (ret < 0) return gnutls_assert_val (ret); server_write_key_size = EXPORT_FINAL_KEY_SIZE; pos += key_size; } if (_gnutls_sset_datum (&client_write->key, client_write_key, client_write_key_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n", client_write_key_size, _gnutls_bin2hex (client_write_key, client_write_key_size, buf, sizeof (buf), NULL)); if (_gnutls_sset_datum (&server_write->key, server_write_key, server_write_key_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n", server_write_key_size, _gnutls_bin2hex (server_write_key, server_write_key_size, buf, sizeof (buf), NULL)); } /* IV generation in export and non export ciphers. */ if (IV_size > 0 && export_flag == 0) { if (_gnutls_sset_datum (&client_write->IV, &key_block[pos], IV_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); pos += IV_size; if (_gnutls_sset_datum (&server_write->IV, &key_block[pos], IV_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); pos += IV_size; } else if (IV_size > 0 && export_flag != 0) { opaque iv_block[MAX_CIPHER_BLOCK_SIZE * 2]; if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_hash_md5 ("", 0, rrnd, GNUTLS_RANDOM_SIZE * 2, IV_size, iv_block); if (ret < 0) return gnutls_assert_val (ret); ret = _gnutls_ssl3_hash_md5 ("", 0, rnd, GNUTLS_RANDOM_SIZE * 2, IV_size, &iv_block[IV_size]); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, "", 0, ivblock, ivblock_length, rrnd, 2 * GNUTLS_RANDOM_SIZE, IV_size * 2, iv_block); } if (ret < 0) return gnutls_assert_val (ret); if (_gnutls_sset_datum (&client_write->IV, iv_block, IV_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); if (_gnutls_sset_datum (&server_write->IV, &iv_block[IV_size], IV_size) < 0) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); } return 0; }
static int generate_normal_master (gnutls_session_t session, int keep_premaster) { int ret = 0; char buf[512]; _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size, _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf, sizeof (buf))); _gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32, _gnutls_bin2hex (session-> security_parameters.client_random, 32, buf, sizeof (buf))); _gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32, _gnutls_bin2hex (session-> security_parameters.server_random, 32, buf, sizeof (buf))); if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1]; memcpy (rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); ret = _gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session-> security_parameters.master_secret); } else if (session->security_parameters.extensions.oprfi_client_len > 0 && session->security_parameters.extensions.oprfi_server_len > 0) { opaque *rnd; size_t rndlen = 2 * GNUTLS_RANDOM_SIZE; rndlen += session->security_parameters.extensions.oprfi_client_len; rndlen += session->security_parameters.extensions.oprfi_server_len; rnd = gnutls_malloc (rndlen + 1); if (!rnd) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_hard_log ("INT: CLIENT OPRFI[%d]: %s\n", session->security_parameters.extensions. oprfi_server_len, _gnutls_bin2hex (session-> security_parameters.extensions. oprfi_client, session-> security_parameters.extensions. oprfi_client_len, buf, sizeof (buf))); _gnutls_hard_log ("INT: SERVER OPRFI[%d]: %s\n", session->security_parameters.extensions. oprfi_server_len, _gnutls_bin2hex (session-> security_parameters.extensions. oprfi_server, session-> security_parameters.extensions. oprfi_server_len, buf, sizeof (buf))); memcpy (rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (rnd + GNUTLS_RANDOM_SIZE, session->security_parameters.extensions.oprfi_client, session->security_parameters.extensions.oprfi_client_len); memcpy (rnd + GNUTLS_RANDOM_SIZE + session->security_parameters.extensions.oprfi_client_len, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy (rnd + GNUTLS_RANDOM_SIZE + session->security_parameters.extensions.oprfi_client_len + GNUTLS_RANDOM_SIZE, session->security_parameters.extensions.oprfi_server, session->security_parameters.extensions.oprfi_server_len); ret = _gnutls_PRF (session, PREMASTER.data, PREMASTER.size, MASTER_SECRET, strlen (MASTER_SECRET), rnd, rndlen, GNUTLS_MASTER_SIZE, session->security_parameters.master_secret); gnutls_free (rnd); } else { opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1]; memcpy (rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); ret = _gnutls_PRF (session, PREMASTER.data, PREMASTER.size, MASTER_SECRET, strlen (MASTER_SECRET), rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session->security_parameters.master_secret); } /* TLS/IA inner secret is derived from the master secret. */ memcpy (session->security_parameters.inner_secret, session->security_parameters.master_secret, GNUTLS_MASTER_SIZE); if (!keep_premaster) _gnutls_free_datum (&PREMASTER); if (ret < 0) return ret; _gnutls_hard_log ("INT: MASTER SECRET: %s\n", _gnutls_bin2hex (session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE, buf, sizeof (buf))); return ret; }
static int generate_normal_master (gnutls_session_t session, int keep_premaster) { int ret = 0; char buf[512]; _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size, _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf, sizeof (buf), NULL)); _gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32, _gnutls_bin2hex (session-> security_parameters.client_random, 32, buf, sizeof (buf), NULL)); _gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32, _gnutls_bin2hex (session-> security_parameters.server_random, 32, buf, sizeof (buf), NULL)); if (gnutls_protocol_get_version (session) == GNUTLS_SSL3) { opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1]; memcpy (rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); ret = _gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session-> security_parameters.master_secret); } else { opaque rnd[2 * GNUTLS_RANDOM_SIZE + 1]; memcpy (rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy (&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); ret = _gnutls_PRF (session, PREMASTER.data, PREMASTER.size, MASTER_SECRET, MASTER_SECRET_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session->security_parameters.master_secret); } if (!keep_premaster) _gnutls_free_datum (&PREMASTER); if (ret < 0) return ret; _gnutls_hard_log ("INT: MASTER SECRET: %s\n", _gnutls_bin2hex (session-> security_parameters.master_secret, GNUTLS_MASTER_SIZE, buf, sizeof (buf), NULL)); return ret; }
/* here we generate the TLS Master secret. */ static int generate_normal_master(gnutls_session_t session, gnutls_datum_t * premaster, int keep_premaster) { int ret = 0; char buf[512]; _gnutls_hard_log("INT: PREMASTER SECRET[%d]: %s\n", premaster->size, _gnutls_bin2hex(premaster->data, premaster->size, buf, sizeof(buf), NULL)); _gnutls_hard_log("INT: CLIENT RANDOM[%d]: %s\n", 32, _gnutls_bin2hex(session->security_parameters. client_random, 32, buf, sizeof(buf), NULL)); _gnutls_hard_log("INT: SERVER RANDOM[%d]: %s\n", 32, _gnutls_bin2hex(session->security_parameters. server_random, 32, buf, sizeof(buf), NULL)); if (session->security_parameters.ext_master_secret == 0) { uint8_t rnd[2 * GNUTLS_RANDOM_SIZE + 1]; memcpy(rnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy(&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); #ifdef ENABLE_SSL3 if (get_num_version(session) == GNUTLS_SSL3) { ret = _gnutls_ssl3_generate_random(premaster->data, premaster->size, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session->security_parameters. master_secret); } else #endif ret = _gnutls_PRF(session, premaster->data, premaster->size, MASTER_SECRET, MASTER_SECRET_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, GNUTLS_MASTER_SIZE, session->security_parameters. master_secret); } else { gnutls_datum_t shash = {NULL, 0}; /* draft-ietf-tls-session-hash-02 */ ret = _gnutls_handshake_get_session_hash(session, &shash); if (ret < 0) return gnutls_assert_val(ret); #ifdef ENABLE_SSL3 if (get_num_version(session) == GNUTLS_SSL3) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); #endif ret = _gnutls_PRF(session, premaster->data, premaster->size, EXT_MASTER_SECRET, EXT_MASTER_SECRET_SIZE, shash.data, shash.size, GNUTLS_MASTER_SIZE, session->security_parameters. master_secret); gnutls_free(shash.data); } write_nss_key_log(session, premaster); if (!keep_premaster) _gnutls_free_temp_key_datum(premaster); if (ret < 0) return ret; _gnutls_hard_log("INT: MASTER SECRET: %s\n", _gnutls_bin2hex(session->security_parameters. master_secret, GNUTLS_MASTER_SIZE, buf, sizeof(buf), NULL)); return ret; }
/* This function is to be called after handshake, when master_secret, * client_random and server_random have been initialized. * This function creates the keys and stores them into pending session. * (session->cipher_specs) */ int _gnutls_set_keys (gnutls_session_t session, int hash_size, int IV_size, int key_size, int export_flag) { /* FIXME: This function is too long */ opaque *key_block; opaque rnd[2 * TLS_RANDOM_SIZE]; opaque rrnd[2 * TLS_RANDOM_SIZE]; int pos, ret; int block_size; char buf[65]; if (session->cipher_specs.generated_keys != 0) { /* keys have already been generated. * reset generated_keys and exit normally. */ session->cipher_specs.generated_keys = 0; return 0; } block_size = 2 * hash_size + 2 * key_size; if (export_flag == 0) block_size += 2 * IV_size; key_block = gnutls_secure_malloc (block_size); if (key_block == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } memcpy (rnd, session->security_parameters.server_random, TLS_RANDOM_SIZE); memcpy (&rnd[TLS_RANDOM_SIZE], session->security_parameters.client_random, TLS_RANDOM_SIZE); memcpy (rrnd, session->security_parameters.client_random, TLS_RANDOM_SIZE); memcpy (&rrnd[TLS_RANDOM_SIZE], session->security_parameters.server_random, TLS_RANDOM_SIZE); if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_generate_random (session-> security_parameters. master_secret, TLS_MASTER_SIZE, rnd, 2 * TLS_RANDOM_SIZE, block_size, key_block); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, session->security_parameters.master_secret, TLS_MASTER_SIZE, keyexp, keyexp_length, rnd, 2 * TLS_RANDOM_SIZE, block_size, key_block); } if (ret < 0) { gnutls_assert (); gnutls_free (key_block); return ret; } _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size, _gnutls_bin2hex (key_block, block_size, buf, sizeof (buf))); pos = 0; if (hash_size > 0) { if (_gnutls_sset_datum (&session->cipher_specs.client_write_mac_secret, &key_block[pos], hash_size) < 0) { gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } pos += hash_size; if (_gnutls_sset_datum (&session->cipher_specs.server_write_mac_secret, &key_block[pos], hash_size) < 0) { gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } pos += hash_size; } if (key_size > 0) { opaque *client_write_key, *server_write_key; int client_write_key_size, server_write_key_size; int free_keys = 0; if (export_flag == 0) { client_write_key = &key_block[pos]; client_write_key_size = key_size; pos += key_size; server_write_key = &key_block[pos]; server_write_key_size = key_size; pos += key_size; } else { /* export */ free_keys = 1; client_write_key = gnutls_secure_malloc (EXPORT_FINAL_KEY_SIZE); if (client_write_key == NULL) { gnutls_assert (); gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } server_write_key = gnutls_secure_malloc (EXPORT_FINAL_KEY_SIZE); if (server_write_key == NULL) { gnutls_assert (); gnutls_free (key_block); gnutls_free (client_write_key); return GNUTLS_E_MEMORY_ERROR; } /* generate the final keys */ if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_hash_md5 (&key_block[pos], key_size, rrnd, 2 * TLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, client_write_key); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, &key_block[pos], key_size, cliwrite, cliwrite_length, rrnd, 2 * TLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, client_write_key); } if (ret < 0) { gnutls_assert (); gnutls_free (key_block); gnutls_free (server_write_key); gnutls_free (client_write_key); return ret; } client_write_key_size = EXPORT_FINAL_KEY_SIZE; pos += key_size; if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_hash_md5 (&key_block[pos], key_size, rnd, 2 * TLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, server_write_key); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, &key_block[pos], key_size, servwrite, servwrite_length, rrnd, 2 * TLS_RANDOM_SIZE, EXPORT_FINAL_KEY_SIZE, server_write_key); } if (ret < 0) { gnutls_assert (); gnutls_free (key_block); gnutls_free (server_write_key); gnutls_free (client_write_key); return ret; } server_write_key_size = EXPORT_FINAL_KEY_SIZE; pos += key_size; } if (_gnutls_sset_datum (&session->cipher_specs.client_write_key, client_write_key, client_write_key_size) < 0) { gnutls_free (key_block); gnutls_free (server_write_key); gnutls_free (client_write_key); return GNUTLS_E_MEMORY_ERROR; } _gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n", client_write_key_size, _gnutls_bin2hex (client_write_key, client_write_key_size, buf, sizeof (buf))); if (_gnutls_sset_datum (&session->cipher_specs.server_write_key, server_write_key, server_write_key_size) < 0) { gnutls_free (key_block); gnutls_free (server_write_key); gnutls_free (client_write_key); return GNUTLS_E_MEMORY_ERROR; } _gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n", server_write_key_size, _gnutls_bin2hex (server_write_key, server_write_key_size, buf, sizeof (buf))); if (free_keys != 0) { gnutls_free (server_write_key); gnutls_free (client_write_key); } } /* IV generation in export and non export ciphers. */ if (IV_size > 0 && export_flag == 0) { if (_gnutls_sset_datum (&session->cipher_specs.client_write_IV, &key_block[pos], IV_size) < 0) { gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } pos += IV_size; if (_gnutls_sset_datum (&session->cipher_specs.server_write_IV, &key_block[pos], IV_size) < 0) { gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } pos += IV_size; } else if (IV_size > 0 && export_flag != 0) { opaque *iv_block = gnutls_alloca (IV_size * 2); if (iv_block == NULL) { gnutls_assert (); gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } if (session->security_parameters.version == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_hash_md5 ("", 0, rrnd, TLS_RANDOM_SIZE * 2, IV_size, iv_block); if (ret < 0) { gnutls_assert (); gnutls_free (key_block); gnutls_afree (iv_block); return ret; } ret = _gnutls_ssl3_hash_md5 ("", 0, rnd, TLS_RANDOM_SIZE * 2, IV_size, &iv_block[IV_size]); } else { /* TLS 1.0 */ ret = _gnutls_PRF (session, "", 0, ivblock, ivblock_length, rrnd, 2 * TLS_RANDOM_SIZE, IV_size * 2, iv_block); } if (ret < 0) { gnutls_assert (); gnutls_afree (iv_block); gnutls_free (key_block); return ret; } if (_gnutls_sset_datum (&session->cipher_specs.client_write_IV, iv_block, IV_size) < 0) { gnutls_afree (iv_block); gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } if (_gnutls_sset_datum (&session->cipher_specs.server_write_IV, &iv_block[IV_size], IV_size) < 0) { gnutls_afree (iv_block); gnutls_free (key_block); return GNUTLS_E_MEMORY_ERROR; } gnutls_afree (iv_block); } gnutls_free (key_block); session->cipher_specs.generated_keys = 1; return 0; }
/* This function is to be called after handshake, when master_secret, * client_random and server_random have been initialized. * This function creates the keys and stores them into pending session. * (session->cipher_specs) */ static int _gnutls_set_keys(gnutls_session_t session, record_parameters_st * params, int hash_size, int IV_size, int key_size) { /* FIXME: This function is too long */ uint8_t rnd[2 * GNUTLS_RANDOM_SIZE]; uint8_t rrnd[2 * GNUTLS_RANDOM_SIZE]; int pos, ret; int block_size; char buf[65]; /* avoid using malloc */ uint8_t key_block[2 * MAX_HASH_SIZE + 2 * MAX_CIPHER_KEY_SIZE + 2 * MAX_CIPHER_BLOCK_SIZE]; record_state_st *client_write, *server_write; if (session->security_parameters.entity == GNUTLS_CLIENT) { client_write = ¶ms->write; server_write = ¶ms->read; } else { client_write = ¶ms->read; server_write = ¶ms->write; } block_size = 2 * hash_size + 2 * key_size; block_size += 2 * IV_size; memcpy(rnd, session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); memcpy(&rnd[GNUTLS_RANDOM_SIZE], session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy(rrnd, session->security_parameters.client_random, GNUTLS_RANDOM_SIZE); memcpy(&rrnd[GNUTLS_RANDOM_SIZE], session->security_parameters.server_random, GNUTLS_RANDOM_SIZE); if (get_num_version(session) == GNUTLS_SSL3) { /* SSL 3 */ ret = _gnutls_ssl3_generate_random (session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block); } else { /* TLS 1.0 */ ret = _gnutls_PRF(session, session->security_parameters.master_secret, GNUTLS_MASTER_SIZE, keyexp, keyexp_length, rnd, 2 * GNUTLS_RANDOM_SIZE, block_size, key_block); } if (ret < 0) return gnutls_assert_val(ret); _gnutls_hard_log("INT: KEY BLOCK[%d]: %s\n", block_size, _gnutls_bin2hex(key_block, block_size, buf, sizeof(buf), NULL)); pos = 0; if (hash_size > 0) { if (_gnutls_set_datum (&client_write->mac_secret, &key_block[pos], hash_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos += hash_size; if (_gnutls_set_datum (&server_write->mac_secret, &key_block[pos], hash_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos += hash_size; } if (key_size > 0) { uint8_t *client_write_key, *server_write_key; int client_write_key_size, server_write_key_size; client_write_key = &key_block[pos]; client_write_key_size = key_size; pos += key_size; server_write_key = &key_block[pos]; server_write_key_size = key_size; pos += key_size; if (_gnutls_set_datum (&client_write->key, client_write_key, client_write_key_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log("INT: CLIENT WRITE KEY [%d]: %s\n", client_write_key_size, _gnutls_bin2hex(client_write_key, client_write_key_size, buf, sizeof(buf), NULL)); if (_gnutls_set_datum (&server_write->key, server_write_key, server_write_key_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log("INT: SERVER WRITE KEY [%d]: %s\n", server_write_key_size, _gnutls_bin2hex(server_write_key, server_write_key_size, buf, sizeof(buf), NULL)); } /* IV generation in export and non export ciphers. */ if (IV_size > 0) { if (_gnutls_set_datum (&client_write->IV, &key_block[pos], IV_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); pos += IV_size; if (_gnutls_set_datum (&server_write->IV, &key_block[pos], IV_size) < 0) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_hard_log("INT: CLIENT WRITE IV [%d]: %s\n", client_write->IV.size, _gnutls_bin2hex(client_write->IV.data, client_write->IV.size, buf, sizeof(buf), NULL)); _gnutls_hard_log("INT: SERVER WRITE IV [%d]: %s\n", server_write->IV.size, _gnutls_bin2hex(server_write->IV.data, server_write->IV.size, buf, sizeof(buf), NULL)); } return 0; }