*/
int _gnutls_encrypt(GNUTLS_STATE state, const char* headers, int headers_size,
const char *data, size_t data_size,
- uint8 ** ciphertext, ContentType type, int random_pad)
+ opaque * ciphertext, int ciphertext_size, ContentType type, int random_pad)
{
gnutls_datum plain = { (char*)data, data_size };
- gnutls_datum comp, ciph;
- int err;
+ gnutls_datum comp;
+ int ret;
int free_comp = 1;
if (plain.size == 0 || is_write_comp_null( state)==0) {
comp = plain;
free_comp = 0;
} else {
- err = _gnutls_plaintext2TLSCompressed(state, &comp, plain);
- if (err < 0) {
+ ret = _gnutls_m_plaintext2compressed(state, &comp, plain);
+ if (ret < 0) {
gnutls_assert();
- return err;
+ return ret;
}
}
- err = _gnutls_compressed2TLSCiphertext(state, &ciph, comp, type, headers_size, random_pad);
- if (err < 0) {
- gnutls_assert();
- return err;
- }
+ ret = _gnutls_compressed2ciphertext(state, &ciphertext[headers_size],
+ ciphertext_size - headers_size, comp, type, random_pad);
if (free_comp)
gnutls_free_datum(&comp);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+
/* copy the headers */
- memcpy( ciph.data, headers, headers_size);
- WRITEuint16( ciph.size - headers_size, &ciph.data[3]);
-
- *ciphertext = ciph.data;
+ memcpy( ciphertext, headers, headers_size);
+ WRITEuint16( ret, &ciphertext[3]);
- return ciph.size;
+ return ret+headers_size;
}
int _gnutls_decrypt(GNUTLS_STATE state, char *ciphertext,
- size_t ciphertext_size, uint8 ** data,
+ size_t ciphertext_size, uint8 * data, int data_size,
ContentType type)
{
gnutls_datum gtxt;
- gnutls_datum gcomp;
gnutls_datum gcipher;
int ret;
- *data = NULL;
-
if (ciphertext_size == 0)
return 0;
gcipher.size = ciphertext_size;
gcipher.data = ciphertext;
- ret = _gnutls_ciphertext2TLSCompressed(state, &gcomp, gcipher, type);
+ ret = _gnutls_ciphertext2compressed(state, data, data_size, gcipher, type);
if (ret < 0) {
return ret;
}
- if (gcomp.size==0 || is_read_comp_null( state)==0) {
- gtxt = gcomp;
+ if (ret==0 || is_read_comp_null( state)==0) {
+ /* ret == ret */
+
} else {
- ret = _gnutls_TLSCompressed2plaintext(state, >xt, gcomp);
+ gnutls_datum gcomp;
+
+ /* compression has this malloc overhead.
+ */
+
+ gcomp.data = data;
+ gcomp.size = ret;
+ ret = _gnutls_m_compressed2plaintext(state, >xt, gcomp);
if (ret < 0) {
- gnutls_free_datum(&gcomp);
return ret;
}
+
+ if (gtxt.size > data_size) {
+ gnutls_assert();
+ gnutls_free_datum( >xt);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ memcpy( data, gtxt.data, gtxt.size);
+ ret = gtxt.size;
- gnutls_free_datum(&gcomp);
+ gnutls_free_datum( >xt);
}
- ret = gtxt.size;
-
- *data = gtxt.data;
-
return ret;
}
}
}
+inline
+static int calc_enc_length( GNUTLS_STATE state, int data_size, int hash_size, uint8* pad, int random_pad,
+ CipherType block_algo, int blocksize)
+{
+uint8 rand;
+int length;
+
+ *pad = 0;
+
+ switch ( block_algo) {
+ case CIPHER_STREAM:
+ length =
+ data_size + hash_size;
+
+ break;
+ case CIPHER_BLOCK:
+ if (_gnutls_get_random(&rand, 1, GNUTLS_WEAK_RANDOM) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* make rand a multiple of blocksize */
+ if ( state->security_parameters.version == GNUTLS_SSL3 ||
+ random_pad==0) {
+ rand = 0;
+ } else {
+ rand = (rand / blocksize) * blocksize;
+ /* added to avoid the case of pad calculated 0
+ * seen below for pad calculation.
+ */
+ if (rand > blocksize) rand-=blocksize;
+ }
+
+ length =
+ data_size +
+ hash_size;
+
+ *pad = (uint8) (blocksize - (length % blocksize)) + rand;
+
+ length += *pad;
+
+ break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+ return length;
+}
+
/* This is the actual encryption
- * (and also keeps some space for headers (RECORD_HEADER_SIZE) in the
- * encrypted data)
+ * Encrypts the given compressed datum, and puts the result to cipher_data,
+ * which has cipher_size size.
+ * return the actual encrypted data length.
*/
-int _gnutls_compressed2TLSCiphertext(GNUTLS_STATE state,
- gnutls_datum*
- cipher,
+int _gnutls_compressed2ciphertext(GNUTLS_STATE state,
+ opaque* cipher_data, int cipher_size,
gnutls_datum compressed, ContentType _type,
- int headers_size,
int random_pad)
{
uint8 MAC[MAX_HASH_SIZE];
uint16 c_length;
- uint8 *data;
uint8 pad;
- uint8 rand;
uint64 seq_num;
int length,ret;
GNUTLS_MAC_HANDLE td;
int blocksize =
_gnutls_cipher_get_block_size(state->security_parameters.
write_bulk_cipher_algorithm);
+ CipherType block_algo = _gnutls_cipher_is_block(state->security_parameters.write_bulk_cipher_algorithm);
+
ver = gnutls_protocol_get_version( state);
minor = _gnutls_version_get_minor( ver);
_gnutls_hmac(td, compressed.data, compressed.size);
mac_deinit( td, MAC, ver);
}
- switch (_gnutls_cipher_is_block(state->security_parameters.write_bulk_cipher_algorithm)) {
- case CIPHER_STREAM:
- length =
- compressed.size + hash_size;
-
- data = gnutls_malloc(length+headers_size);
- if (data==NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- break;
- case CIPHER_BLOCK:
- if (_gnutls_get_random(&rand, 1, GNUTLS_WEAK_RANDOM) < 0) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- /* make rand a multiple of blocksize */
- if ( state->security_parameters.version == GNUTLS_SSL3 ||
- random_pad==0) {
- rand = 0;
- } else {
- rand = (rand / blocksize) * blocksize;
- /* added to avoid the case of pad calculated 0
- * seen below for pad calculation.
- */
- if (rand > blocksize) rand-=blocksize;
- }
-
- length =
- compressed.size +
- hash_size;
-
- pad = (uint8) (blocksize - (length % blocksize)) + rand;
- length += pad;
- data = gnutls_malloc(length+headers_size);
- if (data==NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- memset(&data[headers_size + length - pad], pad - 1, pad);
+ /* Calculate the encrypted length (padding etc.)
+ */
+ length = calc_enc_length( state, compressed.size, hash_size, &pad, random_pad, block_algo,
+ blocksize);
+ if (length < 0) {
+ gnutls_assert();
+ return length;
+ }
- break;
- default:
+ /* copy the encrypted data to cipher_data.
+ */
+ if (cipher_size < length) {
gnutls_assert();
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ return GNUTLS_E_MEMORY_ERROR;
}
- memcpy(&data[headers_size], compressed.data, compressed.size);
- memcpy(&data[compressed.size+headers_size], MAC, hash_size);
+ memcpy(cipher_data, compressed.data, compressed.size);
+ if (hash_size > 0)
+ memcpy(&cipher_data[compressed.size], MAC, hash_size);
+ if (block_algo==CIPHER_BLOCK && pad > 0)
+ memset(&cipher_data[ length - pad], pad - 1, pad);
+
+ /* Actual encryption (inplace).
+ */
if ( (ret = _gnutls_cipher_encrypt(state->connection_state.
- write_cipher_state, &data[headers_size],
+ write_cipher_state, cipher_data,
length)) < 0) {
- gnutls_free( data);
return ret;
}
- cipher->data = data;
- cipher->size = length + headers_size;
- return 0;
-
+ return length;
}
-int _gnutls_ciphertext2TLSCompressed(GNUTLS_STATE state,
- gnutls_datum *
- compress,
+/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
+ * Returns the actual compressed packet size.
+ */
+int _gnutls_ciphertext2compressed(GNUTLS_STATE state,
+ opaque* compress_data, int compress_size,
gnutls_datum ciphertext, uint8 type)
{
uint8 MAC[MAX_HASH_SIZE];
uint16 c_length;
- uint8 *data;
uint8 pad;
uint64 seq_num;
uint16 length;
return GNUTLS_E_UNKNOWN_MAC_ALGORITHM;
}
- /* actual encryption
+
+ /* actual decryption (inplace)
*/
switch (_gnutls_cipher_is_block(state->security_parameters.read_bulk_cipher_algorithm)) {
case CIPHER_STREAM:
return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
}
- if (length > 0) {
- data = gnutls_malloc(length);
- if (data==NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
- } else data = NULL;
- if (data!=NULL) {
- memcpy(data, ciphertext.data, length);
+ /* copy the decrypted stuff to compress_data.
+ */
+ if (compress_size < length) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
}
- compress->data = data;
- compress->size = length;
+ memcpy( compress_data, ciphertext.data, length);
+
- c_length = CONVuint16((uint16) compress->size);
+ c_length = CONVuint16((uint16) length);
seq_num = CONVuint64( &state->connection_state.read_sequence_number);
+ /* Pass the type, version, length and compressed through
+ * MAC.
+ */
if (td != GNUTLS_MAC_FAILED) {
_gnutls_hmac(td, UINT64DATA(seq_num), 8);
}
_gnutls_hmac(td, &c_length, 2);
- if (data!=NULL)
- _gnutls_hmac(td, data, compress->size);
+ if (length!=0)
+ _gnutls_hmac(td, compress_data, length);
mac_deinit( td, MAC, ver);
}
/* HMAC was not the same.
*/
if (memcmp
- (MAC, &ciphertext.data[compress->size], hash_size) != 0) {
- gnutls_free( data);
+ (MAC, &ciphertext.data[length], hash_size) != 0) {
gnutls_assert();
return GNUTLS_E_DECRYPTION_FAILED;
}
- return 0;
+ return length;
}
static
ssize_t _gnutls_create_empty_record( GNUTLS_STATE state, ContentType type,
- opaque** erecord)
+ opaque* erecord, int erecord_size)
{
int cipher_size;
int retval;
uint8 headers[5];
GNUTLS_Version lver;
- *erecord = NULL;
-
-
if (type!=GNUTLS_APPLICATION_DATA ||
_gnutls_cipher_is_block( gnutls_cipher_get(state))!=CIPHER_BLOCK)
/* alert messages and stream ciphers
data2send = 0;
- cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, NULL, 0, erecord, type, 0);
+ cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, NULL, 0, erecord, erecord_size, type, 0);
if (cipher_size <= 0) {
gnutls_assert();
if (cipher_size==0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
uint8 *cipher;
int cipher_size;
int retval, ret;
- int data2send;
+ int data2send_size;
uint8 headers[5];
const uint8 *data=_data;
GNUTLS_Version lver;
(int) uint64touint32(&state->connection_state.write_sequence_number), _gnutls_packet2str(type), type, sizeofdata);
if ( sizeofdata > MAX_RECORD_SIZE)
- data2send = MAX_RECORD_SIZE;
+ data2send_size = MAX_RECORD_SIZE;
else
- data2send = sizeofdata;
+ data2send_size = sizeofdata;
/* Only encrypt if we don't have data to send
* from the previous run. - probably interrupted.
/* if this protection has been disabled
*/
if (state->gnutls_internals.cbc_protection_hack!=0) {
+ erecord_size = MAX_RECORD_OVERHEAD;
+ erecord = gnutls_alloca( erecord_size);
+ if (erecord==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
erecord_size =
- _gnutls_create_empty_record( state, type, &erecord);
+ _gnutls_create_empty_record( state, type, erecord, erecord_size);
if (erecord_size < 0) {
gnutls_assert();
return erecord_size;
/* now proceed to packet encryption
*/
- cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, data, data2send, &cipher, type, 1);
+ cipher_size = data2send_size + MAX_RECORD_OVERHEAD;
+ cipher = gnutls_alloca( cipher_size);
+ if (cipher==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, data, data2send_size, cipher,
+ cipher_size, type, 1);
if (cipher_size <= 0) {
gnutls_assert();
if (cipher_size==0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
- gnutls_free( erecord);
+ gnutls_afree( erecord);
+ gnutls_afree( cipher);
return cipher_size; /* error */
}
- retval = data2send;
- state->gnutls_internals.record_send_buffer_user_size = data2send;
+ retval = data2send_size;
+ state->gnutls_internals.record_send_buffer_user_size = data2send_size;
/* increase sequence number
*/
if (uint64pp( &state->connection_state.write_sequence_number) != 0) {
_gnutls_session_invalidate( state);
gnutls_assert();
- gnutls_free( erecord);
+ gnutls_afree( erecord);
+ gnutls_afree( cipher);
return GNUTLS_E_RECORD_LIMIT_REACHED;
}
ret = _gnutls_io_write_buffered2( state, erecord, erecord_size, cipher, cipher_size);
- gnutls_free( erecord);
- gnutls_free( cipher);
+ gnutls_afree( erecord);
+ gnutls_afree( cipher);
}
if ( ret != cipher_size + erecord_size) {
/* decrypt the data we got
*/
- tmplen = _gnutls_decrypt( state, ciphertext, length, &tmpdata, recv_type);
+ tmplen = length + MAX_RECORD_OVERHEAD;
+ tmpdata = gnutls_alloca( tmplen);
+ if (tmpdata==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ tmplen = _gnutls_decrypt( state, ciphertext, length, tmpdata, tmplen, recv_type);
if (tmplen < 0) {
_gnutls_session_unresumable( state);
_gnutls_session_invalidate( state);
+ gnutls_afree(tmpdata);
gnutls_assert();
return tmplen;
}
if (tmplen!=sizeofdata) { /* sizeofdata should be 1 */
gnutls_assert();
- gnutls_free(tmpdata);
+ gnutls_afree(tmpdata);
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
memcpy( data, tmpdata, sizeofdata);
- gnutls_free(tmpdata);
+ gnutls_afree(tmpdata);
return tmplen;
}
/* increase sequence number */
if (uint64pp( &state->connection_state.read_sequence_number)!=0) {
_gnutls_session_invalidate( state);
- gnutls_free(tmpdata);
+ gnutls_afree(tmpdata);
gnutls_assert();
return GNUTLS_E_RECORD_LIMIT_REACHED;
}
if ( (ret=_gnutls_record_check_type( state, recv_type, type, htype, tmpdata, tmplen)) < 0) {
- gnutls_free( tmpdata);
+ gnutls_afree(tmpdata);
if (ret==GNUTLS_E_INT_RET_0) return 0;
gnutls_assert();
return ret;
}
- gnutls_free( tmpdata);
+ gnutls_afree(tmpdata);
/* Get Application data from buffer */
if ((type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE) && (recv_type == type)) {