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 cipher_algo; gnutls_mac_algorithm_t mac_algo; gnutls_compression_method_t comp_algo; record_parameters_st *params; int ret; gnutls_protocol_t ver = gnutls_protocol_get_version (session); 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); 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_hmac_get_algo_len (mac_algo); 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, ver, 1, ¶ms->read); if (ret < 0) return gnutls_assert_val (ret); ret = _gnutls_init_record_state (params, ver, 0, ¶ms->write); if (ret < 0) return gnutls_assert_val (ret); params->record_sw_size = 0; _gnutls_record_log ("REC[%p]: Epoch #%u ready\n", session, params->epoch); params->initialized = 1; return 0; }
/* returns overhead imposed by the record layer (encryption/compression) * etc. It does not include the record layer headers, since the caller * needs to cope with rounding to multiples of blocksize, and the header * is outside that. * * blocksize: will contain the block size when padding may be required or 1 * * It may return a negative error code on error. */ static int record_overhead_rt(gnutls_session_t session, unsigned int *blocksize) { record_parameters_st *params; int total = 0, ret, iv_size; if (session->internals.initial_negotiation_completed == 0) return GNUTLS_E_INVALID_REQUEST; ret = _gnutls_epoch_get (session, EPOCH_WRITE_CURRENT, ¶ms); if (ret < 0) return gnutls_assert_val(ret); /* requires padding */ iv_size = _gnutls_cipher_get_iv_size(params->cipher_algorithm); if (_gnutls_cipher_is_block (params->cipher_algorithm) == CIPHER_BLOCK) { *blocksize = iv_size; total += iv_size; /* iv_size == block_size in DTLS */ /* We always pad with at least one byte; never 0. */ total++; } else { *blocksize = 1; } if (params->mac_algorithm == GNUTLS_MAC_AEAD) total += _gnutls_cipher_get_tag_size(params->cipher_algorithm); else { ret = _gnutls_hmac_get_algo_len(params->mac_algorithm); if (ret < 0) return gnutls_assert_val(ret); total+=ret; } if (params->compression_algorithm != GNUTLS_COMP_NULL) total += EXTRA_COMP_SIZE; return total; }
int _gnutls_set_write_keys (gnutls_session_t session) { int hash_size; int IV_size; int key_size, export_flag; gnutls_cipher_algorithm_t algo; gnutls_mac_algorithm_t mac_algo; mac_algo = session->security_parameters.write_mac_algorithm; algo = session->security_parameters.write_bulk_cipher_algorithm; 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); }
int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch) { int hash_size; int IV_size; int key_size; gnutls_compression_method_t comp_algo; record_parameters_st *params; int ret; const version_entry_st *ver = get_version(session); if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); 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); comp_algo = params->compression_algorithm; if (_gnutls_cipher_is_ok(params->cipher) == 0 || _gnutls_mac_is_ok(params->mac) == 0) return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); if (_gnutls_cipher_priority(session, params->cipher->id) < 0) return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); if (_gnutls_mac_priority(session, params->mac->id) < 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); if (!_gnutls_version_has_explicit_iv(ver) && _gnutls_cipher_type(params->cipher) == CIPHER_BLOCK) { IV_size = _gnutls_cipher_get_iv_size(params->cipher); } else { IV_size = _gnutls_cipher_get_implicit_iv_size(params->cipher); } key_size = _gnutls_cipher_get_key_size(params->cipher); hash_size = _gnutls_mac_get_key_size(params->mac); params->etm = session->security_parameters.etm; ret = _gnutls_set_keys (session, params, hash_size, IV_size, key_size); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_init_record_state(params, ver, 1, ¶ms->read); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_init_record_state(params, ver, 0, ¶ms->write); if (ret < 0) return gnutls_assert_val(ret); params->record_sw_size = 0; _gnutls_record_log("REC[%p]: Epoch #%u ready\n", session, params->epoch); params->initialized = 1; return 0; }
static int decrypt_packet_tls13(gnutls_session_t session, gnutls_datum_t *ciphertext, gnutls_datum_t *plain, content_type_t *type, record_parameters_st *params, gnutls_uint64 *sequence) { uint8_t nonce[MAX_CIPHER_IV_SIZE]; size_t length, length_to_decrypt; int ret; const version_entry_st *ver = get_version(session); unsigned int tag_size = params->read.aead_tag_size; unsigned iv_size; unsigned j; volatile unsigned length_set; uint8_t aad[5]; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (params->cipher->id == GNUTLS_CIPHER_NULL) { if (plain->size < ciphertext->size) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); length = ciphertext->size; memcpy(plain->data, ciphertext->data, length); return length; } iv_size = _gnutls_cipher_get_iv_size(params->cipher); /* The way AEAD ciphers are defined in RFC5246, it allows * only stream ciphers. */ if (unlikely(ciphertext->size < tag_size)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); if (unlikely(params->read.iv_size != iv_size || iv_size < 8)) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); memcpy(nonce, params->read.iv, params->read.iv_size); memxor(&nonce[iv_size-8], UINT64DATA(*sequence), 8); length = ciphertext->size - tag_size; length_to_decrypt = ciphertext->size; if (unlikely ((unsigned) length_to_decrypt > plain->size)) { _gnutls_audit_log(session, "Received %u bytes, while expecting less than %u\n", (unsigned int) length_to_decrypt, (unsigned int) plain->size); return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); } aad[0] = GNUTLS_APPLICATION_DATA; aad[1] = 0x03; aad[2] = 0x03; _gnutls_write_uint16(ciphertext->size, &aad[3]); ret = gnutls_aead_cipher_decrypt(¶ms->read.ctx.aead, nonce, iv_size, aad, sizeof(aad), tag_size, ciphertext->data, length_to_decrypt, plain->data, &length); if (unlikely(ret < 0)) return gnutls_assert_val(ret); /* 1 octet for content type */ if (length > max_decrypted_size(session) + 1) { _gnutls_audit_log (session, "Received packet with illegal length: %u\n", (unsigned int) length); return gnutls_assert_val(GNUTLS_E_RECORD_OVERFLOW); } length_set = 0; /* now figure the actual data size. We intentionally iterate through all data, * to avoid leaking the padding length due to timing differences in processing. */ for (j=length;j>0;j--) { if (plain->data[j-1]!=0 && length_set == 0) { *type = plain->data[j-1]; length = j-1; length_set = 1; if (!(session->internals.flags & GNUTLS_SAFE_PADDING_CHECK)) break; } } if (!length_set) return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); return length; }