#include <ext_session_ticket.h>
#include <gnutls_mbuffers.h>
#include <gnutls_extensions.h>
+#include <gnutls_constate.h>
#ifdef ENABLE_SESSION_TICKET
return 0;
}
-#define SAVE_WRITE_SECURITY_PARAMETERS \
- do \
- { \
- write_bulk_cipher_algorithm = \
- session->security_parameters.write_bulk_cipher_algorithm; \
- write_mac_algorithm = \
- session->security_parameters.write_mac_algorithm; \
- write_compression_algorithm = \
- session->security_parameters.write_compression_algorithm; \
- } \
- while (0)
-
-#define RESTORE_WRITE_SECURITY_PARAMETERS \
- do \
- { \
- session->security_parameters.write_bulk_cipher_algorithm = \
- write_bulk_cipher_algorithm; \
- session->security_parameters.write_mac_algorithm = \
- write_mac_algorithm; \
- session->security_parameters.write_compression_algorithm = \
- write_compression_algorithm; \
- } \
- while (0)
-
int
_gnutls_send_new_session_ticket (gnutls_session_t session, int again)
{
int ret;
struct ticket ticket;
uint16_t ticket_len;
- gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t write_mac_algorithm;
- gnutls_compression_method_t write_compression_algorithm;
session_ticket_ext_st* priv=NULL;
extension_priv_data_t epriv;
+ uint16_t epoch_saved = session->security_parameters.epoch_write;
if (again == 0)
{
_gnutls_write_connection_state_init() does this job, but it also
triggers encryption, while NewSessionTicket should not be
encrypted in the record layer. */
- SAVE_WRITE_SECURITY_PARAMETERS;
- ret = _gnutls_set_write_cipher (session,
- _gnutls_cipher_suite_get_cipher_algo
- (&session->
- security_parameters.current_cipher_suite));
+ ret = _gnutls_epoch_set_keys (session, session->security_parameters.epoch_next);
if (ret < 0)
- return ret;
+ {
+ gnutls_assert ();
+ return ret;
+ }
- ret = _gnutls_set_write_mac (session,
- _gnutls_cipher_suite_get_mac_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (ret < 0)
- return ret;
- ret = _gnutls_set_write_compression (session,
- session->
- internals.compression_method);
- if (ret < 0)
- return ret;
+ session->security_parameters.epoch_write = session->security_parameters.epoch_next;
ret = encrypt_ticket (session, priv, &ticket);
- RESTORE_WRITE_SECURITY_PARAMETERS;
+ session->security_parameters.epoch_write = epoch_saved;
if (ret < 0)
{
gnutls_assert ();
_gnutls_record_log ("REC: Sending Alert[%d|%d] - %s\n", data[0],
data[1], name);
- if ((ret = _gnutls_send_int (session, GNUTLS_ALERT, -1, data, 2, MBUFFER_FLUSH)) >= 0)
+ if ((ret = _gnutls_send_int (session, GNUTLS_ALERT, -1, EPOCH_WRITE_CURRENT, data, 2, MBUFFER_FLUSH)) >= 0)
return 0;
else
return ret;
{
ret = _gnutls_send_int (session, GNUTLS_HANDSHAKE,
session->internals.handshake_send_buffer_htype,
+ EPOCH_WRITE_CURRENT,
msg.data, msg.size, 0/* do not flush */);
if (ret >= 0)
inline static int
is_write_comp_null (gnutls_session_t session)
{
- if (session->security_parameters.write_compression_algorithm ==
- GNUTLS_COMP_NULL)
+ record_parameters_st *record_params;
+
+ _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, &record_params);
+ if (record_params->compression_algorithm == GNUTLS_COMP_NULL)
return 0;
return 1;
inline static int
is_read_comp_null (gnutls_session_t session)
{
- if (session->security_parameters.read_compression_algorithm ==
- GNUTLS_COMP_NULL)
+ record_parameters_st *record_params;
+
+ _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
+ if (record_params->compression_algorithm == GNUTLS_COMP_NULL)
return 0;
return 1;
_gnutls_encrypt (gnutls_session_t session, const opaque * headers,
size_t headers_size, const opaque * data,
size_t data_size, opaque * ciphertext,
- size_t ciphertext_size, content_type_t type, int random_pad)
+ size_t ciphertext_size, content_type_t type, int random_pad,
+ record_parameters_st *params)
{
gnutls_datum_t plain;
gnutls_datum_t comp;
/* Here comp is allocated and must be
* freed.
*/
- ret = _gnutls_m_plaintext2compressed (session, &comp, &plain);
+ ret = _gnutls_m_plaintext2compressed (session, &comp, &plain, params);
if (ret < 0)
{
gnutls_assert ();
ret = _gnutls_compressed2ciphertext (session, &ciphertext[headers_size],
ciphertext_size - headers_size,
- comp, type, random_pad);
+ comp, type, random_pad, params);
if (free_comp)
_gnutls_free_datum (&comp);
int
_gnutls_decrypt (gnutls_session_t session, opaque * ciphertext,
size_t ciphertext_size, uint8_t * data,
- size_t max_data_size, content_type_t type)
+ size_t max_data_size, content_type_t type,
+ record_parameters_st *params)
{
gnutls_datum_t gtxt;
gnutls_datum_t gcipher;
ret =
_gnutls_ciphertext2compressed (session, data, max_data_size,
- gcipher, type);
+ gcipher, type, params);
if (ret < 0)
{
return ret;
gcomp.data = data;
gcomp.size = ret;
- ret = _gnutls_m_compressed2plaintext (session, >xt, &gcomp);
+ ret = _gnutls_m_compressed2plaintext (session, >xt, &gcomp, params);
if (ret < 0)
{
return ret;
_gnutls_compressed2ciphertext (gnutls_session_t session,
opaque * cipher_data, int cipher_size,
gnutls_datum_t compressed,
- content_type_t _type, int random_pad)
+ content_type_t _type, int random_pad,
+ record_parameters_st *params)
{
uint8_t MAC[MAX_HASH_SIZE];
uint16_t c_length;
opaque preamble[PREAMBLE_SIZE];
int preamble_size;
int hash_size =
- _gnutls_hash_get_algo_len (session->
- security_parameters.write_mac_algorithm);
+ _gnutls_hash_get_algo_len (params->mac_algorithm);
int blocksize =
- gnutls_cipher_get_block_size (session->
- security_parameters.write_bulk_cipher_algorithm);
+ gnutls_cipher_get_block_size (params->cipher_algorithm);
cipher_type_t block_algo =
- _gnutls_cipher_is_block (session->
- security_parameters.write_bulk_cipher_algorithm);
+ _gnutls_cipher_is_block (params->cipher_algorithm);
opaque *data_ptr;
int ver = gnutls_protocol_get_version (session);
c_length = _gnutls_conv_uint16 (compressed.size);
- if (session->security_parameters.write_mac_algorithm != GNUTLS_MAC_NULL)
+ if (params->mac_algorithm != GNUTLS_MAC_NULL)
{ /* actually when the algorithm in not the NULL one */
digest_hd_st td;
- ret = mac_init (&td, session->security_parameters.write_mac_algorithm,
- session->connection_state.write_mac_secret.data,
- session->connection_state.write_mac_secret.size, ver);
+ ret = mac_init (&td, params->mac_algorithm,
+ params->write.mac_secret.data,
+ params->write.mac_secret.size, ver);
if (ret < 0)
{
}
preamble_size =
make_preamble (UINT64DATA
- (session->connection_state.write_sequence_number),
+ (params->write.sequence_number),
type, c_length, ver, preamble);
mac_hash (&td, preamble, preamble_size, ver);
mac_hash (&td, compressed.data, compressed.size, ver);
/* Actual encryption (inplace).
*/
ret =
- _gnutls_cipher_encrypt (&session->connection_state.write_cipher_state,
+ _gnutls_cipher_encrypt (¶ms->write.cipher_state,
cipher_data, length);
if (ret < 0)
{
_gnutls_ciphertext2compressed (gnutls_session_t session,
opaque * compress_data,
int compress_size,
- gnutls_datum_t ciphertext, uint8_t type)
+ gnutls_datum_t ciphertext, uint8_t type,
+ record_parameters_st *params)
{
uint8_t MAC[MAX_HASH_SIZE];
uint16_t c_length;
int preamble_size;
int ver = gnutls_protocol_get_version (session);
int hash_size =
- _gnutls_hash_get_algo_len (session->
- security_parameters.read_mac_algorithm);
+ _gnutls_hash_get_algo_len (params->mac_algorithm);
blocksize =
- gnutls_cipher_get_block_size (session->
- security_parameters.read_bulk_cipher_algorithm);
+ gnutls_cipher_get_block_size (params->cipher_algorithm);
/* actual decryption (inplace)
*/
- switch (_gnutls_cipher_is_block
- (session->security_parameters.read_bulk_cipher_algorithm))
+ switch (_gnutls_cipher_is_block (params->cipher_algorithm))
{
case CIPHER_STREAM:
if ((ret =
- _gnutls_cipher_decrypt (&session->
- connection_state.read_cipher_state,
+ _gnutls_cipher_decrypt (¶ms->read.cipher_state,
ciphertext.data, ciphertext.size)) < 0)
{
gnutls_assert ();
}
if ((ret =
- _gnutls_cipher_decrypt (&session->
- connection_state.read_cipher_state,
+ _gnutls_cipher_decrypt (¶ms->read.cipher_state,
ciphertext.data, ciphertext.size)) < 0)
{
gnutls_assert ();
/* Pass the type, version, length and compressed through
* MAC.
*/
- if (session->security_parameters.read_mac_algorithm != GNUTLS_MAC_NULL)
+ if (params->mac_algorithm != GNUTLS_MAC_NULL)
{
digest_hd_st td;
- ret = mac_init (&td, session->security_parameters.read_mac_algorithm,
- session->connection_state.read_mac_secret.data,
- session->connection_state.read_mac_secret.size, ver);
+ ret = mac_init (&td, params->mac_algorithm,
+ params->read.mac_secret.data,
+ params->read.mac_secret.size, ver);
if (ret < 0)
{
preamble_size =
make_preamble (UINT64DATA
- (session->connection_state.read_sequence_number), type,
+ (params->read.sequence_number), type,
c_length, ver, preamble);
mac_hash (&td, preamble, preamble_size, ver);
if (length > 0)
size_t headers_size, const opaque * data,
size_t data_size, opaque * ciphertext,
size_t ciphertext_size, content_type_t type,
- int random_pad);
+ int random_pad, record_parameters_st *params);
int _gnutls_decrypt (gnutls_session_t session, opaque * ciphertext,
size_t ciphertext_size, uint8_t * data, size_t data_size,
- content_type_t type);
+ content_type_t type, record_parameters_st *params);
int _gnutls_compressed2ciphertext (gnutls_session_t session,
opaque * cipher_data, int cipher_size,
gnutls_datum_t compressed,
- content_type_t _type, int random_pad);
+ content_type_t _type, int random_pad,
+ record_parameters_st *params);
int _gnutls_ciphertext2compressed (gnutls_session_t session,
opaque * compress_data,
int compress_size,
- gnutls_datum_t ciphertext, uint8_t type);
+ gnutls_datum_t ciphertext, uint8_t type,
+ record_parameters_st *params);
#include "gnutls_int.h"
#include "gnutls_compress.h"
#include "gnutls_errors.h"
+#include "gnutls_constate.h"
#include <gnutls_algorithms.h>
#include <gnutls/gnutls.h>
int
_gnutls_m_plaintext2compressed (gnutls_session_t session,
gnutls_datum_t * compressed,
- const gnutls_datum_t * plaintext)
+ const gnutls_datum_t * plaintext,
+ const record_parameters_st *params)
{
int size;
opaque *data;
size =
- _gnutls_compress (session->connection_state.write_compression_state,
+ _gnutls_compress (params->write.compression_state,
plaintext->data, plaintext->size, &data,
MAX_RECORD_SEND_SIZE + EXTRA_COMP_SIZE);
if (size < 0)
int
_gnutls_m_compressed2plaintext (gnutls_session_t session,
gnutls_datum_t * plain,
- const gnutls_datum_t * compressed)
+ const gnutls_datum_t * compressed,
+ const record_parameters_st *params)
{
int size;
opaque *data;
size =
- _gnutls_decompress (session->connection_state.read_compression_state,
+ _gnutls_decompress (params->read.compression_state,
compressed->data, compressed->size, &data,
MAX_RECORD_RECV_SIZE);
if (size < 0)
int _gnutls_m_plaintext2compressed (gnutls_session_t session,
gnutls_datum_t * compressed,
- const gnutls_datum_t * plaintext);
+ const gnutls_datum_t * plaintext,
+ const record_parameters_st *params);
int _gnutls_m_compressed2plaintext (gnutls_session_t session,
gnutls_datum_t * plain,
- const gnutls_datum_t * compressed);
+ const gnutls_datum_t * compressed,
+ const record_parameters_st *params);
/* Algorithm handling. */
int _gnutls_supported_compression_methods (gnutls_session_t session,
#include <gnutls_datum.h>
#include <gnutls_state.h>
#include <gnutls_extensions.h>
+#include <gnutls_buffers.h>
static const char keyexp[] = "key expansion";
static const int keyexp_length = sizeof (keyexp) - 1;
* (session->cipher_specs)
*/
static int
-_gnutls_set_keys (gnutls_session_t session, int hash_size, int IV_size,
+_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
/* 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;
- 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;
- }
+ 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)
}
if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
+ 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));
- _gnutls_free_datum (&session->cipher_specs.server_write_mac_secret);
- _gnutls_free_datum (&session->cipher_specs.client_write_mac_secret);
- _gnutls_free_datum (&session->cipher_specs.server_write_IV);
- _gnutls_free_datum (&session->cipher_specs.client_write_IV);
- _gnutls_free_datum (&session->cipher_specs.server_write_key);
- _gnutls_free_datum (&session->cipher_specs.client_write_key);
-
pos = 0;
if (hash_size > 0)
{
if (_gnutls_sset_datum
- (&session->cipher_specs.client_write_mac_secret,
+ (&client_write->mac_secret,
&key_block[pos], hash_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
+
pos += hash_size;
if (_gnutls_sset_datum
- (&session->cipher_specs.server_write_mac_secret,
+ (&server_write->mac_secret,
&key_block[pos], hash_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
+
pos += hash_size;
}
}
if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
+ return gnutls_assert_val (ret);
client_write_key_size = EXPORT_FINAL_KEY_SIZE;
pos += key_size;
}
if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
+ return gnutls_assert_val (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, client_write_key_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ 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,
sizeof (buf), NULL));
if (_gnutls_sset_datum
- (&session->cipher_specs.server_write_key,
+ (&server_write->key,
server_write_key, server_write_key_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
_gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n",
server_write_key_size,
if (IV_size > 0 && export_flag == 0)
{
if (_gnutls_sset_datum
- (&session->cipher_specs.client_write_IV, &key_block[pos],
+ (&client_write->IV, &key_block[pos],
IV_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
+
pos += IV_size;
if (_gnutls_sset_datum
- (&session->cipher_specs.server_write_IV, &key_block[pos],
+ (&server_write->IV, &key_block[pos],
IV_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
+
pos += IV_size;
}
IV_size, iv_block);
if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
+ return gnutls_assert_val (ret);
+
ret = _gnutls_ssl3_hash_md5 ("", 0, rnd,
GNUTLS_RANDOM_SIZE * 2,
}
if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
+ return gnutls_assert_val (ret);
if (_gnutls_sset_datum
- (&session->cipher_specs.client_write_IV, iv_block, IV_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ (&client_write->IV, iv_block, IV_size) < 0)
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
if (_gnutls_sset_datum
- (&session->cipher_specs.server_write_IV,
+ (&server_write->IV,
&iv_block[IV_size], IV_size) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
}
- session->cipher_specs.generated_keys = 1;
-
return 0;
}
static int
-_gnutls_set_read_keys (gnutls_session_t session)
+_gnutls_init_record_state (record_parameters_st *params, int read,
+ record_state_st *state)
{
- int hash_size;
- int IV_size;
- int key_size, export_flag;
- gnutls_cipher_algorithm_t algo;
+ int ret;
+
+ ret = _gnutls_cipher_init (&state->cipher_state,
+ params->cipher_algorithm,
+ &state->key, &state->IV);
+ if (ret < 0
+ && params->cipher_algorithm != GNUTLS_CIPHER_NULL)
+ return gnutls_assert_val (ret);
+
+ state->compression_state =
+ _gnutls_comp_init (params->compression_algorithm, read);
+
+ if (state->compression_state == GNUTLS_COMP_FAILED)
+ return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
+
+ return 0;
+}
+
+int
+_gnutls_epoch_set_cipher_suite (gnutls_session_t session,
+ int epoch_rel,
+ cipher_suite_st *suite)
+{
+ gnutls_cipher_algorithm_t cipher_algo;
gnutls_mac_algorithm_t mac_algo;
+ record_parameters_st *params;
+ int ret;
- mac_algo = session->security_parameters.read_mac_algorithm;
- algo = session->security_parameters.read_bulk_cipher_algorithm;
+ ret = _gnutls_epoch_get (session, epoch_rel, ¶ms);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
- hash_size = _gnutls_hash_get_algo_len (mac_algo);
- IV_size = _gnutls_cipher_get_iv_size (algo);
- key_size = gnutls_cipher_get_key_size (algo);
- export_flag = _gnutls_cipher_get_export_flag (algo);
+ if (params->initialized
+ || params->cipher_algorithm != GNUTLS_CIPHER_UNKNOWN
+ || params->mac_algorithm != GNUTLS_MAC_UNKNOWN)
+ return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
- return _gnutls_set_keys (session, hash_size, IV_size, key_size,
- export_flag);
+ cipher_algo =_gnutls_cipher_suite_get_cipher_algo (suite);
+ mac_algo = _gnutls_cipher_suite_get_mac_algo (suite);
+
+ if (_gnutls_cipher_is_ok (cipher_algo) != 0
+ || _gnutls_mac_is_ok (mac_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
+
+ params->cipher_algorithm = cipher_algo;
+ params->mac_algorithm = mac_algo;
+
+ return 0;
}
-static int
-_gnutls_set_write_keys (gnutls_session_t session)
+int
+_gnutls_epoch_set_compression (gnutls_session_t session,
+ int epoch_rel,
+ gnutls_compression_method_t comp_algo)
+{
+ record_parameters_st *params;
+ int ret;
+
+ ret = _gnutls_epoch_get (session, epoch_rel, ¶ms);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
+
+ if (params->initialized
+ || params->compression_algorithm != GNUTLS_COMP_UNKNOWN)
+ return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
+
+ if (_gnutls_compression_is_ok (comp_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
+
+ params->compression_algorithm = comp_algo;
+
+ return 0;
+}
+
+void
+_gnutls_epoch_set_null_algos (gnutls_session_t session,
+ record_parameters_st *params)
+{
+ /* This is only called on startup. We are extra paranoid about this
+ because it may cause unencrypted application data to go out on
+ the wire. */
+ if (params->initialized || params->epoch != 0)
+ {
+ gnutls_assert ();
+ return;
+ }
+
+ params->cipher_algorithm = GNUTLS_CIPHER_NULL;
+ params->mac_algorithm = GNUTLS_MAC_NULL;
+ params->compression_algorithm = GNUTLS_COMP_NULL;
+ params->initialized = 1;
+}
+
+int
+_gnutls_epoch_set_keys (gnutls_session_t session, uint16_t epoch)
{
int hash_size;
int IV_size;
int key_size, export_flag;
- gnutls_cipher_algorithm_t algo;
+ gnutls_cipher_algorithm_t cipher_algo;
gnutls_mac_algorithm_t mac_algo;
+ gnutls_compression_method_t comp_algo;
+ record_parameters_st *params;
+ int ret;
+
+ ret = _gnutls_epoch_get (session, epoch, ¶ms);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
+
+ if (params->initialized)
+ return 0;
+
+ _gnutls_record_log
+ ("REC[%p]: Initializing epoch #%u\n", session, params->epoch);
- mac_algo = session->security_parameters.write_mac_algorithm;
- algo = session->security_parameters.write_bulk_cipher_algorithm;
+ cipher_algo = params->cipher_algorithm;
+ mac_algo = params->mac_algorithm;
+ comp_algo = params->compression_algorithm;
+ if (_gnutls_cipher_is_ok (cipher_algo) != 0
+ || _gnutls_mac_is_ok (mac_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
+
+ if (_gnutls_compression_is_ok (comp_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
+
+ IV_size = _gnutls_cipher_get_iv_size (cipher_algo);
+ key_size = gnutls_cipher_get_key_size (cipher_algo);
+ export_flag = _gnutls_cipher_get_export_flag (cipher_algo);
hash_size = _gnutls_hash_get_algo_len (mac_algo);
- IV_size = _gnutls_cipher_get_iv_size (algo);
- key_size = gnutls_cipher_get_key_size (algo);
- export_flag = _gnutls_cipher_get_export_flag (algo);
- return _gnutls_set_keys (session, hash_size, IV_size, key_size,
- export_flag);
+ ret = _gnutls_set_keys
+ (session, params, hash_size, IV_size, key_size, export_flag);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
+
+ ret = _gnutls_init_record_state (params, 1, ¶ms->read);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
+
+ ret = _gnutls_init_record_state (params, 0, ¶ms->write);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
+
+ _gnutls_record_log
+ ("REC[%p]: Epoch #%u ready\n", session, params->epoch);
+
+ params->initialized = 1;
+ return 0;
}
+
#define CPY_COMMON dst->entity = src->entity; \
dst->kx_algorithm = src->kx_algorithm; \
memcpy( &dst->current_cipher_suite, &src->current_cipher_suite, sizeof(cipher_suite_st)); \
dst->version = src->version
static void
-_gnutls_cpy_read_security_parameters (security_parameters_st *
- dst, security_parameters_st * src)
+_gnutls_set_resumed_parameters (gnutls_session_t session)
{
- CPY_COMMON;
+ security_parameters_st *src = &session->internals.resumed_security_parameters;
+ security_parameters_st *dst = &session->security_parameters;
- dst->read_bulk_cipher_algorithm = src->read_bulk_cipher_algorithm;
- dst->read_mac_algorithm = src->read_mac_algorithm;
- dst->read_compression_algorithm = src->read_compression_algorithm;
-}
-
-static void
-_gnutls_cpy_write_security_parameters (security_parameters_st *
- dst, security_parameters_st * src)
-{
CPY_COMMON;
-
- dst->write_bulk_cipher_algorithm = src->write_bulk_cipher_algorithm;
- dst->write_mac_algorithm = src->write_mac_algorithm;
- dst->write_compression_algorithm = src->write_compression_algorithm;
}
/* Sets the current connection session to conform with the
/* Setup the master secret
*/
if ((ret = _gnutls_generate_master (session, 0)) < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
+ return gnutls_assert_val (ret);
return 0;
}
+
+static int
+_gnutls_check_algos (gnutls_session_t session,
+ cipher_suite_st *suite, gnutls_compression_method_t comp_algo)
+{
+ gnutls_cipher_algorithm_t cipher_algo;
+ gnutls_mac_algorithm_t mac_algo;
+
+ cipher_algo = _gnutls_cipher_suite_get_cipher_algo (suite);
+ mac_algo = _gnutls_cipher_suite_get_mac_algo (suite);
+
+ if (_gnutls_cipher_is_ok (cipher_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
+
+ if (_gnutls_cipher_priority (session, cipher_algo) < 0)
+ return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
+
+
+ if (_gnutls_mac_is_ok (mac_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
+
+ if (_gnutls_mac_priority (session, mac_algo) < 0)
+ return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
+
+
+ if (_gnutls_compression_is_ok (comp_algo) != 0)
+ return gnutls_assert_val (GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM);
+
+ return 0;
+}
+
/* Initializes the read connection session
* (read encrypted data)
*/
int
_gnutls_read_connection_state_init (gnutls_session_t session)
{
- int mac_size;
- int rc;
-
- _gnutls_uint64zero (session->connection_state.read_sequence_number);
+ const uint16_t epoch_next = session->security_parameters.epoch_next;
+ int ret;
-/* Update internals from CipherSuite selected.
- * If we are resuming just copy the connection session
- */
+ /* Update internals from CipherSuite selected.
+ * If we are resuming just copy the connection session
+ */
if (session->internals.resumed == RESUME_FALSE)
{
- rc = _gnutls_set_read_cipher (session,
- _gnutls_cipher_suite_get_cipher_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (rc < 0)
- return rc;
- rc = _gnutls_set_read_mac (session,
- _gnutls_cipher_suite_get_mac_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (rc < 0)
- return rc;
-
- rc = _gnutls_set_kx (session,
- _gnutls_cipher_suite_get_kx_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (rc < 0)
- return rc;
-
- rc = _gnutls_set_read_compression (session,
- session->
- internals.compression_method);
- if (rc < 0)
- return rc;
- }
- else
- { /* RESUME_TRUE */
- _gnutls_cpy_read_security_parameters (&session->security_parameters,
- &session->
- internals.resumed_security_parameters);
- }
+ ret = _gnutls_check_algos (session,
+ &session->security_parameters.current_cipher_suite,
+ session->internals.compression_method);
+ if (ret < 0)
+ return ret;
+ ret = _gnutls_set_kx (session,
+ _gnutls_cipher_suite_get_kx_algo
+ (&session->
+ security_parameters.current_cipher_suite));
+ if (ret < 0)
+ return ret;
+ }
+ else if (session->security_parameters.entity == GNUTLS_CLIENT)
+ _gnutls_set_resumed_parameters (session);
- rc = _gnutls_set_read_keys (session);
- if (rc < 0)
- return rc;
+ ret = _gnutls_epoch_set_keys (session, epoch_next);
+ if (ret < 0)
+ return ret;
_gnutls_handshake_log ("HSK[%p]: Cipher Suite: %s\n",
session,
(&session->
security_parameters.current_cipher_suite));
- if (_gnutls_compression_is_ok
- (session->security_parameters.read_compression_algorithm) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
- }
-
- if (_gnutls_mac_is_ok
- (session->security_parameters.read_mac_algorithm) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
- /* Free all the previous keys/ sessions etc.
- */
- if (session->connection_state.read_mac_secret.data != NULL)
- _gnutls_free_datum (&session->connection_state.read_mac_secret);
-
- _gnutls_cipher_deinit (&session->connection_state.read_cipher_state);
-
- if (session->connection_state.read_compression_state != NULL)
- _gnutls_comp_deinit (session->connection_state.read_compression_state, 1);
-
-
- mac_size =
- _gnutls_hash_get_algo_len (session->
- security_parameters.read_mac_algorithm);
-
- _gnutls_handshake_log
- ("HSK[%p]: Initializing internal [read] cipher sessions\n", session);
-
- switch (session->security_parameters.entity)
- {
- case GNUTLS_SERVER:
- /* initialize cipher session
- */
- rc = _gnutls_cipher_init (&session->connection_state.read_cipher_state,
- session->security_parameters.
- read_bulk_cipher_algorithm,
- &session->cipher_specs.client_write_key,
- &session->cipher_specs.client_write_IV);
- if (rc < 0
- && session->security_parameters.read_bulk_cipher_algorithm !=
- GNUTLS_CIPHER_NULL)
- {
- gnutls_assert ();
- return rc;
- }
-
- /* copy mac secrets from cipherspecs, to connection
- * session.
- */
- if (mac_size > 0)
- {
- if (_gnutls_sset_datum (&session->connection_state.read_mac_secret,
- session->
- cipher_specs.client_write_mac_secret.data,
- session->
- cipher_specs.client_write_mac_secret.size) <
- 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- }
-
- break;
-
- case GNUTLS_CLIENT:
- rc = _gnutls_cipher_init (&session->connection_state.read_cipher_state,
- session->security_parameters.
- read_bulk_cipher_algorithm,
- &session->cipher_specs.server_write_key,
- &session->cipher_specs.server_write_IV);
-
- if (rc < 0
- && session->security_parameters.read_bulk_cipher_algorithm !=
- GNUTLS_CIPHER_NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
-
- /* copy mac secret to connection session
- */
- if (mac_size > 0)
- {
- if (_gnutls_sset_datum (&session->connection_state.read_mac_secret,
- session->
- cipher_specs.server_write_mac_secret.data,
- session->
- cipher_specs.server_write_mac_secret.size) <
- 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
- }
-
- break;
-
- default: /* this check is useless */
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
- session->connection_state.read_compression_state =
- _gnutls_comp_init (session->
- security_parameters.read_compression_algorithm, 1);
-
- if (session->connection_state.read_compression_state == GNUTLS_COMP_FAILED)
- {
- gnutls_assert ();
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
- }
+ session->security_parameters.epoch_read = epoch_next;
+ _gnutls_epoch_gc (session);
return 0;
}
int
_gnutls_write_connection_state_init (gnutls_session_t session)
{
- int mac_size;
- int rc;
-
- _gnutls_uint64zero (session->connection_state.write_sequence_number);
+ const uint16_t epoch_next = session->security_parameters.epoch_next;
+ int ret;
/* Update internals from CipherSuite selected.
* If we are resuming just copy the connection session
*/
if (session->internals.resumed == RESUME_FALSE)
{
- rc = _gnutls_set_write_cipher (session,
- _gnutls_cipher_suite_get_cipher_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (rc < 0)
- return rc;
- rc = _gnutls_set_write_mac (session,
- _gnutls_cipher_suite_get_mac_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (rc < 0)
- return rc;
-
- rc = _gnutls_set_kx (session,
- _gnutls_cipher_suite_get_kx_algo
- (&session->
- security_parameters.current_cipher_suite));
- if (rc < 0)
- return rc;
-
- rc = _gnutls_set_write_compression (session,
- session->
- internals.compression_method);
- if (rc < 0)
- return rc;
- }
- else
- { /* RESUME_TRUE */
- _gnutls_cpy_write_security_parameters (&session->security_parameters,
- &session->
- internals.resumed_security_parameters);
- _gnutls_ext_restore_resumed_session(session);
+ ret = _gnutls_check_algos (session,
+ &session->security_parameters.current_cipher_suite,
+ session->internals.compression_method);
+ if (ret < 0)
+ return ret;
+
+ ret = _gnutls_set_kx (session,
+ _gnutls_cipher_suite_get_kx_algo
+ (&session->
+ security_parameters.current_cipher_suite));
+ if (ret < 0)
+ return ret;
}
+ else if (session->security_parameters.entity == GNUTLS_SERVER)
+ _gnutls_set_resumed_parameters (session);
- rc = _gnutls_set_write_keys (session);
- if (rc < 0)
- return rc;
+ ret = _gnutls_epoch_set_keys (session, epoch_next);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
_gnutls_handshake_log ("HSK[%p]: Cipher Suite: %s\n", session,
_gnutls_cipher_suite_get_name
(&session->
security_parameters.current_cipher_suite));
- if (_gnutls_compression_is_ok
- (session->security_parameters.write_compression_algorithm) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
- }
-
- if (_gnutls_mac_is_ok
- (session->security_parameters.write_mac_algorithm) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
-
-
- /* Free all the previous keys/ sessions etc.
- */
- if (session->connection_state.write_mac_secret.data != NULL)
- _gnutls_free_datum (&session->connection_state.write_mac_secret);
-
- _gnutls_cipher_deinit (&session->connection_state.write_cipher_state);
-
- if (session->connection_state.write_compression_state != NULL)
- _gnutls_comp_deinit (session->connection_state.write_compression_state,
- 0);
-
- mac_size =
- _gnutls_hash_get_algo_len (session->
- security_parameters.write_mac_algorithm);
-
_gnutls_handshake_log
("HSK[%p]: Initializing internal [write] cipher sessions\n", session);
- switch (session->security_parameters.entity)
- {
- case GNUTLS_SERVER:
- /* initialize cipher session
- */
- rc = _gnutls_cipher_init (&session->connection_state.write_cipher_state,
- session->
- security_parameters.write_bulk_cipher_algorithm,
- &session->cipher_specs.server_write_key,
- &session->cipher_specs.server_write_IV);
-
- if (rc < 0
- && session->security_parameters.write_bulk_cipher_algorithm !=
- GNUTLS_CIPHER_NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
+ session->security_parameters.epoch_write = epoch_next;
+ _gnutls_epoch_gc (session);
- /* copy mac secrets from cipherspecs, to connection
- * session.
- */
- if (mac_size > 0)
- {
- if (_gnutls_sset_datum (&session->connection_state.write_mac_secret,
- session->
- cipher_specs.server_write_mac_secret.data,
- session->
- cipher_specs.server_write_mac_secret.size) <
- 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ return 0;
+}
- }
+/* Sets the specified kx algorithm into pending session
+ */
+int
+_gnutls_set_kx (gnutls_session_t session, gnutls_kx_algorithm_t algo)
+{
+ if (_gnutls_kx_is_ok (algo) == 0)
+ {
+ session->security_parameters.kx_algorithm = algo;
+ }
+ else
+ return gnutls_assert_val (GNUTLS_E_INTERNAL_ERROR);
- break;
+ if (_gnutls_kx_priority (session, algo) < 0)
+ return gnutls_assert_val (GNUTLS_E_UNWANTED_ALGORITHM);
- case GNUTLS_CLIENT:
- rc = _gnutls_cipher_init (&session->connection_state.write_cipher_state,
- session->
- security_parameters.write_bulk_cipher_algorithm,
- &session->cipher_specs.client_write_key,
- &session->cipher_specs.client_write_IV);
+ return 0;
+}
- if (rc < 0
- && session->security_parameters.write_bulk_cipher_algorithm !=
- GNUTLS_CIPHER_NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
+static inline int
+epoch_resolve(gnutls_session_t session,
+ unsigned int epoch_rel, uint16_t *epoch_out)
+{
+ switch (epoch_rel)
+ {
+ case EPOCH_READ_CURRENT:
+ *epoch_out = session->security_parameters.epoch_read;
+ return 0;
- /* copy mac secret to connection session
- */
- if (mac_size > 0)
- {
- if (_gnutls_sset_datum (&session->connection_state.write_mac_secret,
- session->
- cipher_specs.client_write_mac_secret.data,
- session->
- cipher_specs.client_write_mac_secret.size) <
- 0)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
- }
+ case EPOCH_WRITE_CURRENT:
+ *epoch_out = session->security_parameters.epoch_write;
+ return 0;
- break;
+ case EPOCH_NEXT:
+ *epoch_out = session->security_parameters.epoch_next;
+ return 0;
default:
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
+ if (epoch_rel > 0xffffu)
+ return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
+ *epoch_out = epoch_rel;
+ return 0;
+ }
+}
- session->connection_state.write_compression_state =
- _gnutls_comp_init (session->
- security_parameters.write_compression_algorithm, 0);
+static inline record_parameters_st**
+epoch_get_slot(gnutls_session_t session, uint16_t epoch)
+{
+ uint16_t epoch_index =
+ epoch - session->security_parameters.epoch_min;
- if (session->connection_state.write_compression_state == GNUTLS_COMP_FAILED)
+ if (epoch_index >= MAX_EPOCH_INDEX)
{
gnutls_assert ();
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ return NULL;
}
- return 0;
+ /* The slot may still be empty (NULL) */
+ return &session->record_parameters[epoch_index];
}
-/* Sets the specified cipher into the pending session
- */
int
-_gnutls_set_read_cipher (gnutls_session_t session,
- gnutls_cipher_algorithm_t algo)
+_gnutls_epoch_get (gnutls_session_t session, unsigned int epoch_rel,
+ record_parameters_st **params_out)
{
+ uint16_t epoch;
+ record_parameters_st **params;
+ int ret;
- if (_gnutls_cipher_is_ok (algo) == 0)
- {
- if (_gnutls_cipher_priority (session, algo) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_UNWANTED_ALGORITHM;
- }
+ ret = epoch_resolve (session, epoch_rel, &epoch);
+ if (ret < 0)
+ return gnutls_assert_val (ret);
- session->security_parameters.read_bulk_cipher_algorithm = algo;
+ params = epoch_get_slot (session, epoch);
+ if (params == NULL || *params == NULL)
+ return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
+ *params_out = *params;
return 0;
-
}
int
-_gnutls_set_write_cipher (gnutls_session_t session,
- gnutls_cipher_algorithm_t algo)
+_gnutls_epoch_alloc(gnutls_session_t session, uint16_t epoch,
+ record_parameters_st **out)
{
+ record_parameters_st **slot;
- if (_gnutls_cipher_is_ok (algo) == 0)
- {
- if (_gnutls_cipher_priority (session, algo) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_UNWANTED_ALGORITHM;
- }
+ _gnutls_record_log
+ ("REC[%p]: Allocating epoch #%u\n", session, epoch);
- session->security_parameters.write_bulk_cipher_algorithm = algo;
+ slot = epoch_get_slot(session, epoch);
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
+ /* If slot out of range or not empty. */
+ if (slot == NULL)
+ return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
- return 0;
+ if(*slot != NULL)
+ return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST);
-}
+ *slot = gnutls_calloc (1, sizeof (record_parameters_st));
+ if (*slot == NULL)
+ return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR);
+ (*slot)->epoch = epoch;
+ (*slot)->cipher_algorithm = GNUTLS_CIPHER_UNKNOWN;
+ (*slot)->mac_algorithm = GNUTLS_MAC_UNKNOWN;
+ (*slot)->compression_algorithm = GNUTLS_COMP_UNKNOWN;
-/* Sets the specified algorithm into pending compression session
- */
-int
-_gnutls_set_read_compression (gnutls_session_t session,
- gnutls_compression_method_t algo)
-{
+ if (out != NULL)
+ *out = *slot;
- if (_gnutls_compression_is_ok (algo) == 0)
- {
- session->security_parameters.read_compression_algorithm = algo;
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
- }
return 0;
-
}
-int
-_gnutls_set_write_compression (gnutls_session_t session,
- gnutls_compression_method_t algo)
+static inline int
+epoch_alive (gnutls_session_t session, record_parameters_st *params)
{
+ const security_parameters_st *sp = &session->security_parameters;
- if (_gnutls_compression_is_ok (algo) == 0)
- {
- session->security_parameters.write_compression_algorithm = algo;
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
- }
- return 0;
-
+ /* DTLS will, in addition, need to check the epoch timeout value. */
+ return (params->epoch == sp->epoch_read
+ || params->epoch == sp->epoch_write
+ || params->epoch == sp->epoch_next);
}
-/* Sets the specified kx algorithm into pending session
- */
-int
-_gnutls_set_kx (gnutls_session_t session, gnutls_kx_algorithm_t algo)
+void
+_gnutls_epoch_gc (gnutls_session_t session)
{
-
- if (_gnutls_kx_is_ok (algo) == 0)
- {
- session->security_parameters.kx_algorithm = algo;
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
- if (_gnutls_kx_priority (session, algo) < 0)
- {
- gnutls_assert ();
- /* we shouldn't get here */
- return GNUTLS_E_UNWANTED_ALGORITHM;
- }
-
- return 0;
-
+ int i, j;
+ unsigned int min_index = 0;
+
+ _gnutls_record_log
+ ("REC[%p]: Start of epoch cleanup\n", session);
+
+ /* Free all dead cipher state */
+ for(i=0; i < MAX_EPOCH_INDEX; i++)
+ if (session->record_parameters[i] != NULL
+ && !epoch_alive (session, session->record_parameters[i]))
+ {
+ _gnutls_epoch_free (session, session->record_parameters[i]);
+ session->record_parameters[i] = NULL;
+ }
+
+ /* Look for contiguous NULLs at the start of the array */
+ for(i=0; i < MAX_EPOCH_INDEX && session->record_parameters[i] == NULL; i++);
+ min_index = i;
+
+ /* Pick up the slack in the epoch window. */
+ for(i=0, j=min_index; j < MAX_EPOCH_INDEX; i++, j++)
+ session->record_parameters[i] = session->record_parameters[j];
+
+ /* Set the new epoch_min */
+ if (session->record_parameters[0] != NULL)
+ session->security_parameters.epoch_min = session->record_parameters[0]->epoch;
+
+ _gnutls_record_log
+ ("REC[%p]: End of epoch cleanup\n", session);
}
-/* Sets the specified mac algorithm into pending session */
-int
-_gnutls_set_read_mac (gnutls_session_t session, gnutls_mac_algorithm_t algo)
+static inline void
+free_record_state (record_state_st *state, int read)
{
+ _gnutls_free_datum (&state->mac_secret);
+ _gnutls_free_datum (&state->IV);
+ _gnutls_free_datum (&state->key);
- if (_gnutls_mac_is_ok (algo) == 0)
- {
- session->security_parameters.read_mac_algorithm = algo;
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
- if (_gnutls_mac_priority (session, algo) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_UNWANTED_ALGORITHM;
- }
-
-
- return 0;
+ _gnutls_cipher_deinit (&state->cipher_state);
+ if (state->compression_state != NULL)
+ _gnutls_comp_deinit (state->compression_state, read);
}
-int
-_gnutls_set_write_mac (gnutls_session_t session, gnutls_mac_algorithm_t algo)
+void
+_gnutls_epoch_free (gnutls_session_t session, record_parameters_st *params)
{
+ _gnutls_record_log
+ ("REC[%p]: Epoch #%u freed\n", session, params->epoch);
- if (_gnutls_mac_is_ok (algo) == 0)
- {
- session->security_parameters.write_mac_algorithm = algo;
- }
- else
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
- if (_gnutls_mac_priority (session, algo) < 0)
- {
- gnutls_assert ();
- return GNUTLS_E_UNWANTED_ALGORITHM;
- }
-
-
- return 0;
+ free_record_state (¶ms->read, 1);
+ free_record_state (¶ms->write, 0);
+ gnutls_free (params);
}
*
*/
+#ifndef GNUTLS_CONSTATE_H
+#define GNUTLS_CONSTATE_H
+
+int _gnutls_epoch_set_cipher_suite (gnutls_session_t session, int epoch_rel,
+ cipher_suite_st *suite);
+int _gnutls_epoch_set_compression (gnutls_session_t session, int epoch_rel,
+ gnutls_compression_method_t comp_algo);
+void _gnutls_epoch_set_null_algos (gnutls_session_t session,
+ record_parameters_st *params);
+int _gnutls_epoch_set_keys (gnutls_session_t session, uint16_t epoch);
int _gnutls_connection_state_init (gnutls_session_t session);
int _gnutls_read_connection_state_init (gnutls_session_t session);
int _gnutls_write_connection_state_init (gnutls_session_t session);
-int _gnutls_set_write_cipher (gnutls_session_t session,
- gnutls_cipher_algorithm_t algo);
-int _gnutls_set_write_mac (gnutls_session_t session,
- gnutls_mac_algorithm_t algo);
-int _gnutls_set_read_cipher (gnutls_session_t session,
- gnutls_cipher_algorithm_t algo);
-int _gnutls_set_read_mac (gnutls_session_t session,
- gnutls_mac_algorithm_t algo);
-int _gnutls_set_read_compression (gnutls_session_t session,
- gnutls_compression_method_t algo);
-int _gnutls_set_write_compression (gnutls_session_t session,
- gnutls_compression_method_t algo);
+
int _gnutls_set_kx (gnutls_session_t session, gnutls_kx_algorithm_t algo);
+
+int _gnutls_epoch_get (gnutls_session_t session, unsigned int epoch_rel,
+ record_parameters_st **params_out);
+int _gnutls_epoch_alloc(gnutls_session_t session, uint16_t epoch,
+ record_parameters_st **out);
+void _gnutls_epoch_gc (gnutls_session_t session);
+void _gnutls_epoch_free (gnutls_session_t session, record_parameters_st *state);
+
+#endif
session->internals.resumed_security_parameters.current_cipher_suite.
suite, 2);
- session->internals.compression_method =
- session->internals.resumed_security_parameters.read_compression_algorithm;
+ _gnutls_epoch_set_cipher_suite (session, EPOCH_NEXT,
+ &session->internals.resumed_security_parameters.current_cipher_suite);
+ _gnutls_epoch_set_compression (session, EPOCH_NEXT,
+ session->internals.resumed_compression_method);
+
/* or write_compression_algorithm
* they are the same
*/
_gnutls_cipher_suite_get_name (&cs));
memcpy (session->security_parameters.current_cipher_suite.suite,
ciphers[i].suite, 2);
+ _gnutls_epoch_set_cipher_suite (session, EPOCH_NEXT,
+ &session->security_parameters.current_cipher_suite);
+
+
retval = 0;
goto finish;
}
session->internals.compression_method = method;
gnutls_free (comps);
+ _gnutls_epoch_set_compression (session, EPOCH_NEXT, method);
+
_gnutls_handshake_log
("HSK[%p]: Selected Compression Method: %s\n", session,
gnutls_compression_get_name (session->
}
memcpy (session->security_parameters.current_cipher_suite.suite, suite, 2);
+ _gnutls_epoch_set_cipher_suite (session, EPOCH_NEXT, &session->security_parameters.current_cipher_suite);
_gnutls_handshake_log ("HSK[%p]: Selected cipher suite: %s\n", session,
_gnutls_cipher_suite_get_name
session->internals.compression_method =
_gnutls_compression_get_id (comp_method);
-
+ _gnutls_epoch_set_compression (session, EPOCH_NEXT, session->internals.compression_method);
return 0;
}
session->security_parameters.server_random, GNUTLS_RANDOM_SIZE);
memcpy (session->internals.resumed_security_parameters.client_random,
session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
+
+ _gnutls_epoch_set_cipher_suite
+ (session, EPOCH_NEXT, &session->internals.resumed_security_parameters.current_cipher_suite);
+ _gnutls_epoch_set_compression
+ (session, EPOCH_NEXT, session->internals.resumed_compression_method);
+
session->internals.resumed = RESUME_TRUE; /* we are resuming */
return 0;
gnutls_handshake (gnutls_session_t session)
{
int ret;
+ record_parameters_st *params;
+
+ ret = _gnutls_epoch_get (session, session->security_parameters.epoch_next,
+ ¶ms);
+ if (ret < 0)
+ {
+ /* We assume the epoch is not allocated if _gnutls_epoch_get fails. */
+ ret = _gnutls_epoch_alloc (session, session->security_parameters.epoch_next, NULL);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+ }
if (session->security_parameters.entity == GNUTLS_CLIENT)
{
_gnutls_handshake_io_buffer_clear (session);
_gnutls_handshake_internal_state_clear (session);
+ session->security_parameters.epoch_next++;
+
return 0;
}
typedef struct gnutls_key_st *gnutls_key_st;
+struct record_state_st;
+typedef struct record_state_st record_state_st;
+
+struct record_parameters_st;
+typedef struct record_parameters_st record_parameters_st;
+
/* STATE (cont) */
#include <gnutls_hash_int.h>
{
gnutls_connection_end_t entity;
gnutls_kx_algorithm_t kx_algorithm;
- /* we've got separate write/read bulk/macs because
- * there is a time in handshake where the peer has
- * null cipher and we don't
- */
- gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t read_mac_algorithm;
- gnutls_compression_method_t read_compression_algorithm;
+ handshake_mac_type_t handshake_mac_handle_type; /* one of HANDSHAKE_TYPE_10 and HANDSHAKE_TYPE_12 */
+
+ /* The epoch used to read and write */
+ uint16_t epoch_read;
+ uint16_t epoch_write;
- gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t write_mac_algorithm;
- gnutls_compression_method_t write_compression_algorithm;
- handshake_mac_type_t handshake_mac_handle_type; /* one of HANDSHAKE_TYPE_10 and HANDSHAKE_TYPE_12 */
+ /* The epoch that the next handshake will initialize. */
+ uint16_t epoch_next;
+
+ /* The epoch at index 0 of record_parameters. */
+ uint16_t epoch_min;
/* this is the ciphersuite we are going to use
* moved here from internals in order to be restored
int do_recv_supplemental, do_send_supplemental;
} security_parameters_st;
-/* This structure holds the generated keys
- */
-typedef struct
+struct record_state_st
{
- gnutls_datum_t server_write_mac_secret;
- gnutls_datum_t client_write_mac_secret;
- gnutls_datum_t server_write_IV;
- gnutls_datum_t client_write_IV;
- gnutls_datum_t server_write_key;
- gnutls_datum_t client_write_key;
- int generated_keys; /* zero if keys have not
- * been generated. Non zero
- * otherwise.
- */
-} cipher_specs_st;
+ gnutls_datum_t mac_secret;
+ gnutls_datum_t IV;
+ gnutls_datum_t key;
+ cipher_hd_st cipher_state;
+ comp_hd_t compression_state;
+ uint64 sequence_number;
+};
+/* These are used to resolve relative epochs. These values are just
+ outside the 16 bit range to prevent off-by-one errors. An absolute
+ epoch may be referred to by its numeric id in the range
+ 0x0000-0xffff. */
+#define EPOCH_READ_CURRENT 70000
+#define EPOCH_WRITE_CURRENT 70001
+#define EPOCH_NEXT 70002
-typedef struct
+struct record_parameters_st
{
- cipher_hd_st write_cipher_state;
- cipher_hd_st read_cipher_state;
- comp_hd_t read_compression_state;
- comp_hd_t write_compression_state;
- gnutls_datum_t read_mac_secret;
- gnutls_datum_t write_mac_secret;
- uint64 read_sequence_number;
- uint64 write_sequence_number;
-} conn_stat_st;
+ uint16_t epoch;
+ int initialized;
+
+ gnutls_cipher_algorithm_t cipher_algorithm;
+ gnutls_mac_algorithm_t mac_algorithm;
+ gnutls_compression_method_t compression_algorithm;
+
+ record_state_st read;
+ record_state_st write;
+};
typedef struct
{
/* resumed session */
int resumed:1; /* RESUME_TRUE or FALSE - if we are resuming a session */
security_parameters_st resumed_security_parameters;
+ gnutls_compression_method_t resumed_compression_method;
/* sockets internals */
int lowat;
*/
} internals_st;
+/* Maximum number of epochs we keep around. */
+#define MAX_EPOCH_INDEX 16
+
struct gnutls_session_int
{
security_parameters_st security_parameters;
- cipher_specs_st cipher_specs;
- conn_stat_st connection_state;
+ record_parameters_st *record_parameters[MAX_EPOCH_INDEX];
internals_st internals;
gnutls_key_st key;
};
int _gnutls_uint64pp (uint64 *);
# define _gnutls_uint64zero(x) x.i[0] = x.i[1] = x.i[2] = x.i[3] = x.i[4] = x.i[5] = x.i[6] = x.i[7] = 0
-# define UINT64DATA(x) x.i
+# define UINT64DATA(x) (x.i)
#endif /* GNUTLS_NUM_H */
#include "gnutls_num.h"
#include "gnutls_record.h"
#include "gnutls_datum.h"
+#include "gnutls_constate.h"
#include "ext_max_record.h"
#include <gnutls_state.h>
#include <gnutls_dh.h>
*/
ssize_t
_gnutls_send_int (gnutls_session_t session, content_type_t type,
- gnutls_handshake_description_t htype, const void *_data,
- size_t sizeofdata, unsigned int mflags)
+ gnutls_handshake_description_t htype, unsigned int epoch_rel,
+ const void *_data, size_t sizeofdata, unsigned int mflags)
{
mbuffer_st *bufel;
size_t cipher_size;
int data2send_size;
uint8_t headers[5];
const uint8_t *data = _data;
+ record_parameters_st *record_params;
+ record_state_st *record_state;
+
+ ret = _gnutls_epoch_get (session, epoch_rel, &record_params);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* Safeguard against processing data with an incomplete cipher state. */
+ if (!record_params->initialized)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ record_state = &record_params->write;
/* Do not allow null pointer if the send buffer is empty.
* If the previous send was interrupted then a null pointer is
_gnutls_record_log
("REC[%p]: Sending Packet[%d] %s(%d) with length: %d\n", session,
- (int) _gnutls_uint64touint32 (&session->
- connection_state.write_sequence_number),
+ (int) _gnutls_uint64touint32 (&record_state->sequence_number),
_gnutls_packet2str (type), type, (int) sizeofdata);
if (sizeofdata > MAX_RECORD_SEND_SIZE)
_gnutls_encrypt (session, headers, RECORD_HEADER_SIZE, data,
data2send_size, _mbuffer_get_udata_ptr(bufel), cipher_size, type,
(session->internals.priorities.no_padding ==
- 0) ? 1 : 0);
+ 0) ? 1 : 0, record_params);
if (cipher_size <= 0)
{
gnutls_assert ();
/* increase sequence number
*/
- if (_gnutls_uint64pp
- (&session->connection_state.write_sequence_number) != 0)
+ if (_gnutls_uint64pp (&record_state->sequence_number) != 0)
{
session_invalidate (session);
gnutls_assert ();
session,
(int)
_gnutls_uint64touint32
- (&session->connection_state.write_sequence_number),
+ (&record_state->sequence_number),
_gnutls_packet2str (type), type, (int)cipher_size);
return retval;
_gnutls_handshake_log ("REC[%p]: Sent ChangeCipherSpec\n", session);
if (again == 0)
- return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, 1, MBUFFER_FLUSH);
+ return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, EPOCH_WRITE_CURRENT, data, 1, MBUFFER_FLUSH);
else
{
return _gnutls_io_write_flush (session);
*/
ssize_t
_gnutls_recv_int (gnutls_session_t session, content_type_t type,
- gnutls_handshake_description_t htype, opaque * data,
- size_t sizeofdata)
+ gnutls_handshake_description_t htype,
+ opaque * data, size_t sizeofdata)
{
int decrypted_length;
opaque version[2];
uint16_t header_size;
int empty_packet = 0;
gnutls_datum_t data_enc, tmp;
+ record_parameters_st *record_params;
+ record_state_st *record_state;
+
+ ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* Safeguard against processing data with an incomplete cipher state. */
+ if (!record_params->initialized)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ record_state = &record_params->read;
if (type != GNUTLS_ALERT && (sizeofdata == 0 || data == NULL))
{
_gnutls_record_log
("REC[%p]: Expected Packet[%d] %s(%d) with length: %d\n", session,
- (int) _gnutls_uint64touint32 (&session->
- connection_state.read_sequence_number),
+ (int) _gnutls_uint64touint32 (&record_state->sequence_number),
_gnutls_packet2str (type), type, (int) sizeofdata);
_gnutls_record_log ("REC[%p]: Received Packet[%d] %s(%d) with length: %d\n",
session,
- (int) _gnutls_uint64touint32 (&session->
- connection_state.read_sequence_number),
+ (int) _gnutls_uint64touint32 (&record_state->sequence_number),
_gnutls_packet2str (recv_type), recv_type, length);
if (length > MAX_RECV_SIZE)
*/
ret =
_gnutls_decrypt (session, ciphertext, length, tmp.data, tmp.size,
- recv_type);
+ recv_type, record_params);
if (ret < 0)
{
session_unresumable (session);
_gnutls_record_log
("REC[%p]: Decrypted Packet[%d] %s(%d) with length: %d\n", session,
- (int) _gnutls_uint64touint32 (&session->
- connection_state.read_sequence_number),
+ (int) _gnutls_uint64touint32 (&record_state->sequence_number),
_gnutls_packet2str (recv_type), recv_type, decrypted_length);
/* increase sequence number
*/
- if (_gnutls_uint64pp (&session->connection_state.read_sequence_number) != 0)
+ if (_gnutls_uint64pp (&record_state->sequence_number) != 0)
{
session_invalidate (session);
gnutls_assert ();
gnutls_record_send (gnutls_session_t session, const void *data,
size_t sizeofdata)
{
- return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, data,
- sizeofdata, MBUFFER_FLUSH);
+ return _gnutls_send_int (session, GNUTLS_APPLICATION_DATA, -1, EPOCH_WRITE_CURRENT,
+ data, sizeofdata, MBUFFER_FLUSH);
}
/**
# include <gnutls_buffers.h>
ssize_t _gnutls_send_int (gnutls_session_t session, content_type_t type,
- gnutls_handshake_description_t htype,
+ gnutls_handshake_description_t htype, unsigned int epoch_rel,
const void *data, size_t sizeofdata, unsigned int mflags);
ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type,
gnutls_handshake_description_t, opaque * data,
#include <gnutls_datum.h>
#include <gnutls_num.h>
#include <gnutls_extensions.h>
+#include <gnutls_constate.h>
static int pack_certificate_auth_info (gnutls_session_t,
gnutls_buffer_st * packed_session);
int ret;
int size_offset;
size_t cur_size;
+ record_parameters_st *params;
+
+ if ( session->security_parameters.epoch_read
+ != session->security_parameters.epoch_write)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = _gnutls_epoch_get (session, EPOCH_READ_CURRENT, ¶ms);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
/* move after the auth info stuff.
*/
BUFFER_APPEND(ps, &session->security_parameters.entity, 1);
BUFFER_APPEND(ps, &session->security_parameters.kx_algorithm, 1);
- BUFFER_APPEND(ps, &session->security_parameters.read_bulk_cipher_algorithm, 1);
- BUFFER_APPEND(ps, &session->security_parameters.read_mac_algorithm, 1);
- BUFFER_APPEND(ps, &session->security_parameters.read_compression_algorithm, 1);
- BUFFER_APPEND(ps, &session->security_parameters.write_bulk_cipher_algorithm, 1);
- BUFFER_APPEND(ps, &session->security_parameters.write_mac_algorithm, 1);
- BUFFER_APPEND(ps, &session->security_parameters.write_compression_algorithm, 1);
BUFFER_APPEND(ps, &session->security_parameters.current_cipher_suite.suite[0], 1);
BUFFER_APPEND(ps, &session->security_parameters.current_cipher_suite.suite[1], 1);
+ BUFFER_APPEND(ps, ¶ms->compression_algorithm, 1);
BUFFER_APPEND(ps, &session->security_parameters.cert_type, 1);
BUFFER_APPEND(ps, &session->security_parameters.version, 1);
BUFFER_POP(ps, &session->internals.resumed_security_parameters.entity, 1);
BUFFER_POP(ps, &session->internals.resumed_security_parameters.kx_algorithm, 1);
- BUFFER_POP(ps, &session->internals.resumed_security_parameters.read_bulk_cipher_algorithm, 1);
- BUFFER_POP(ps, &session->internals.resumed_security_parameters.read_mac_algorithm, 1);
- BUFFER_POP(ps, &session->internals.resumed_security_parameters.read_compression_algorithm, 1);
- BUFFER_POP(ps, &session->internals.resumed_security_parameters.write_bulk_cipher_algorithm, 1);
- BUFFER_POP(ps, &session->internals.resumed_security_parameters.write_mac_algorithm, 1);
- BUFFER_POP(ps, &session->internals.resumed_security_parameters.write_compression_algorithm, 1);
BUFFER_POP(ps, &session->internals.resumed_security_parameters.current_cipher_suite.suite[0], 1);
BUFFER_POP(ps, &session->internals.resumed_security_parameters.
current_cipher_suite.suite[1], 1);
+ BUFFER_POP(ps, &session->internals.resumed_compression_method, 1);
BUFFER_POP(ps, &session->internals.resumed_security_parameters.cert_type, 1);
BUFFER_POP(ps, &session->internals.resumed_security_parameters.version, 1);
#include <gnutls_buffers.h>
#include <gnutls_mbuffers.h>
#include <gnutls_state.h>
+#include <gnutls_constate.h>
#include <auth_cert.h>
#include <auth_anon.h>
#include <auth_psk.h>
gnutls_cipher_algorithm_t
gnutls_cipher_get (gnutls_session_t session)
{
- return session->security_parameters.read_bulk_cipher_algorithm;
+ record_parameters_st *record_params;
+ _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
+
+ return record_params->cipher_algorithm;
}
/**
gnutls_mac_algorithm_t
gnutls_mac_get (gnutls_session_t session)
{
- return session->security_parameters.read_mac_algorithm;
+ record_parameters_st *record_params;
+ _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
+
+ return record_params->mac_algorithm;
}
/**
gnutls_compression_method_t
gnutls_compression_get (gnutls_session_t session)
{
- return session->security_parameters.read_compression_algorithm;
+ record_parameters_st *record_params;
+ _gnutls_epoch_get (session, EPOCH_READ_CURRENT, &record_params);
+
+ return record_params->compression_algorithm;
}
/* Check if the given certificate type is supported.
int
gnutls_init (gnutls_session_t * session, gnutls_connection_end_t con_end)
{
+ int ret;
+ record_parameters_st *epoch;
+
*session = gnutls_calloc (1, sizeof (struct gnutls_session_int));
if (*session == NULL)
return GNUTLS_E_MEMORY_ERROR;
- (*session)->security_parameters.entity = con_end;
-
- /* the default certificate type for TLS */
- (*session)->security_parameters.cert_type = DEFAULT_CERT_TYPE;
+ ret = _gnutls_epoch_alloc (*session, 0, &epoch);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
-/* Set the defaults for initial handshake */
- (*session)->security_parameters.read_bulk_cipher_algorithm =
- (*session)->security_parameters.write_bulk_cipher_algorithm =
- GNUTLS_CIPHER_NULL;
+ /* Set all NULL algos on epoch 0 */
+ _gnutls_epoch_set_null_algos(*session, epoch);
- (*session)->security_parameters.read_mac_algorithm =
- (*session)->security_parameters.write_mac_algorithm = GNUTLS_MAC_NULL;
+ (*session)->security_parameters.epoch_next = 1;
- (*session)->security_parameters.read_compression_algorithm =
- GNUTLS_COMP_NULL;
- (*session)->security_parameters.write_compression_algorithm =
- GNUTLS_COMP_NULL;
+ (*session)->security_parameters.entity = con_end;
- (*session)->internals.enable_private = 0;
+ /* the default certificate type for TLS */
+ (*session)->security_parameters.cert_type = DEFAULT_CERT_TYPE;
/* Initialize buffers */
_gnutls_buffer_init (&(*session)->internals.application_data_buffer);
void
gnutls_deinit (gnutls_session_t session)
{
+ unsigned int i;
if (session == NULL)
return;
_gnutls_handshake_io_buffer_clear (session);
_gnutls_ext_free_session_data (session);
- _gnutls_free_datum (&session->connection_state.read_mac_secret);
- _gnutls_free_datum (&session->connection_state.write_mac_secret);
+ for(i=0; i < MAX_EPOCH_INDEX; i++)
+ if (session->record_parameters[i] != NULL)
+ {
+ _gnutls_epoch_free (session, session->record_parameters[i]);
+ session->record_parameters[i] = NULL;
+ }
_gnutls_buffer_clear (&session->internals.ia_data_buffer);
_gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
gnutls_credentials_clear (session);
_gnutls_selected_certs_deinit (session);
- _gnutls_cipher_deinit (&session->connection_state.read_cipher_state);
- _gnutls_cipher_deinit (&session->connection_state.write_cipher_state);
-
- if (session->connection_state.read_compression_state != NULL)
- _gnutls_comp_deinit (session->connection_state.read_compression_state, 1);
- if (session->connection_state.write_compression_state != NULL)
- _gnutls_comp_deinit (session->connection_state.write_compression_state,
- 0);
-
- _gnutls_free_datum (&session->cipher_specs.server_write_mac_secret);
- _gnutls_free_datum (&session->cipher_specs.client_write_mac_secret);
- _gnutls_free_datum (&session->cipher_specs.server_write_IV);
- _gnutls_free_datum (&session->cipher_specs.client_write_IV);
- _gnutls_free_datum (&session->cipher_specs.server_write_key);
- _gnutls_free_datum (&session->cipher_specs.client_write_key);
-
if (session->key != NULL)
{
_gnutls_mpi_release (&session->key->KEY);
memcpy (p + 4, data, sizeofdata);
}
- len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen, MBUFFER_FLUSH);
+ len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, EPOCH_WRITE_CURRENT, p, plen, MBUFFER_FLUSH);
if (p)
gnutls_free (p);