Experimental code.
return 0;
}
+
/* This function is like write. But it does not return -1 on error.
* It does return gnutls_errno instead.
*
}
+/* This is exactly like write_buffered, but will use two buffers to read
+ * from.
+ */
+ssize_t _gnutls_io_write_buffered2( GNUTLS_STATE state, const void *iptr, size_t n, const void* iptr2, size_t n2)
+{
+opaque* sptr;
+
+ sptr = gnutls_malloc( n+n2);
+ if (sptr==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ memcpy( sptr, iptr, n);
+ memcpy( &sptr[n], iptr2, n2);
+
+ return _gnutls_io_write_buffered( state, sptr, n+n2);
+}
+
+
/* This function writes the data that are left in the
* TLS write buffer (ie. because the previous write was
* interrupted.
/*
- * Copyright (C) 2000 Nikos Mavroyanopoulos
+ * Copyright (C) 2000,2001,2002 Nikos Mavroyanopoulos
*
* This file is part of GNUTLS.
*
int _gnutls_io_clear_peeked_data( GNUTLS_STATE state);
ssize_t _gnutls_io_write_buffered( GNUTLS_STATE, const void *iptr, size_t n );
+ssize_t _gnutls_io_write_buffered2( GNUTLS_STATE, const void *iptr, size_t n,
+ const void* iptr2, size_t n2);
int _gnutls_handshake_buffer_get_size( GNUTLS_STATE state);
int _gnutls_handshake_buffer_peek( GNUTLS_STATE state, char *data, int length);
/* returns ciphertext which contains the headers too. This also
* calculates the size in the header field.
+ *
+ * If random pad != 0 then the random pad data will be appended.
*/
int _gnutls_encrypt(GNUTLS_STATE state, const char* headers, int headers_size,
const char *data, size_t data_size,
- uint8 ** ciphertext, ContentType type)
+ uint8 ** ciphertext, ContentType type, int random_pad)
{
gnutls_datum plain = { (char*)data, data_size };
gnutls_datum comp, ciph;
int err;
- if (data_size == 0)
- return 0;
-
err = _gnutls_plaintext2TLSCompressed(state, &comp, plain);
if (err < 0) {
gnutls_assert();
return err;
}
- err = _gnutls_compressed2TLSCiphertext(state, &ciph, comp, type, headers_size);
+ err = _gnutls_compressed2TLSCiphertext(state, &ciph, comp, type, headers_size, random_pad);
if (err < 0) {
gnutls_assert();
return err;
int _gnutls_compressed2TLSCiphertext(GNUTLS_STATE state,
gnutls_datum*
cipher,
- gnutls_datum compressed, ContentType _type, int headers_size)
+ gnutls_datum compressed, ContentType _type,
+ int headers_size,
+ int random_pad)
{
uint8 MAC[MAX_HASH_SIZE];
uint16 c_length;
}
/* make rand a multiple of blocksize */
- if ( state->security_parameters.version == GNUTLS_SSL3) {
+ if ( state->security_parameters.version == GNUTLS_SSL3 ||
+ random_pad==0) {
rand = 0;
} else {
rand = (rand / blocksize) * blocksize;
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
-int _gnutls_encrypt( GNUTLS_STATE state, const char* headers, int headers_size, const char* data, size_t data_size, uint8** ciphertext, ContentType type);
+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);
int _gnutls_decrypt(GNUTLS_STATE state, char *ciphertext,
size_t ciphertext_size, uint8 ** data,
ContentType type);
-int _gnutls_compressed2TLSCiphertext(GNUTLS_STATE state, gnutls_datum* cipher, gnutls_datum compressed, ContentType _type, int headers_size);
+int _gnutls_compressed2TLSCiphertext(GNUTLS_STATE state, gnutls_datum* cipher, gnutls_datum compressed, ContentType _type, int headers_size, int random_pad);
int _gnutls_ciphertext2TLSCompressed(GNUTLS_STATE state, gnutls_datum * compress, gnutls_datum ciphertext, uint8 type);
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
+
res->cert_list_length = gnutls_realloc(res->cert_list_length,
(1+res->ncerts)*sizeof(int));
if (res->cert_list_length == NULL)
iobuf_to_datum(buf, &raw);
cdk_iobuf_close(buf);
- res->ncerts++;
res->pkey = gnutls_realloc(res->pkey,
- (res->ncerts)*sizeof(gnutls_private_key));
+ (res->ncerts+1)*sizeof(gnutls_private_key));
if (res->pkey == NULL)
{
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
+
+ res->ncerts++;
/* ncerts has been incremented before */
rc =_gnutls_openpgp_key2gnutls_key( &res->pkey[res->ncerts-1], raw);
#include "gnutls_record.h"
#include "gnutls_datum.h"
#include "ext_max_record.h"
+#include <gnutls_state.h>
#include <gnutls_alert.h>
#include <gnutls_dh.h>
return 0;
}
+static
+ssize_t gnutls_create_empty_record( GNUTLS_STATE state, ContentType type,
+ opaque** erecord)
+{
+ int cipher_size;
+ int retval;
+ int data2send;
+ 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
+ * do not need this protection
+ */
+ return 0;
+
+ headers[0]=type;
+
+ lver = gnutls_protocol_get_version(state);
+ if (lver==GNUTLS_VERSION_UNKNOWN) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL;
+ }
+
+ headers[1]=_gnutls_version_get_major( lver);
+ headers[2]=_gnutls_version_get_minor( lver);
+
+ data2send = 0;
+
+ cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, NULL, 0, erecord, type, 0);
+ if (cipher_size <= 0) {
+ gnutls_assert();
+ if (cipher_size==0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
+ return cipher_size; /* error */
+ }
+
+ retval = cipher_size;
+
+ /* increase sequence number
+ */
+ if (uint64pp( &state->connection_state.write_sequence_number) != 0) {
+ _gnutls_session_invalidate( state);
+ gnutls_assert();
+ return GNUTLS_E_RECORD_LIMIT_REACHED;
+ }
+
+ return retval;
+}
+
+
/* This function behave exactly like write(). The only difference is
* that it accepts, the gnutls_state and the ContentType of data to
* send (if called by the user the Content is specific)
uint8 headers[5];
const uint8 *data=_data;
GNUTLS_Version lver;
+ int erecord_size = 0;
+ opaque* erecord;
if (sizeofdata == 0 || _data==NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_SESSION;
}
+
+
headers[0]=type;
lver = gnutls_protocol_get_version(state);
retval = state->gnutls_internals.record_send_buffer_user_size;
} else {
- cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, data, data2send, &cipher, type);
+
+ /* Prepend our packet with an empty record. This is to
+ * avoid the recent CBC attacks.
+ */
+ erecord_size =
+ gnutls_create_empty_record( state, type, &erecord);
+ 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);
if (cipher_size <= 0) {
gnutls_assert();
if (cipher_size==0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
+ gnutls_free( erecord);
return cipher_size; /* error */
}
gnutls_assert();
/* FIXME: Somebody has to do rehandshake before that.
*/
+ gnutls_free( erecord);
return GNUTLS_E_RECORD_LIMIT_REACHED;
}
- ret = _gnutls_io_write_buffered( state, cipher, cipher_size);
+ ret = _gnutls_io_write_buffered2( state, erecord, erecord_size, cipher, cipher_size);
+ gnutls_free( erecord);
+ gnutls_free( cipher);
}
- if ( ret != cipher_size) {
- gnutls_free( cipher);
+ if ( ret != cipher_size + erecord_size) {
if ( ret < 0 && gnutls_error_is_fatal(ret)==0) {
/* If we have sent any data then return
* that value.
state->gnutls_internals.record_send_buffer_user_size = 0;
- gnutls_free(cipher);
-
_gnutls_record_log( "REC: Sent Packet[%d] %s(%d) with length: %d\n",
(int) uint64touint32(&state->connection_state.write_sequence_number), _gnutls_packet2str(type), type, cipher_size);
int ret, ret2;
uint16 header_size;
+ begin:
/* default headers for TLS 1.0
*/
header_size = RECORD_HEADER_SIZE;
*/
}
+ /* TLS 1.0 CBC protection. Read the next fragment.
+ */
+ if (ret==0) goto begin;
+
return ret;
}
void _gnutls_state_cert_type_set( GNUTLS_STATE state, CertificateType);
KXAlgorithm gnutls_kx_get( GNUTLS_STATE state);
+GNUTLS_BulkCipherAlgorithm gnutls_cipher_get( GNUTLS_STATE state);
CertificateType gnutls_cert_type_get( GNUTLS_STATE state);
#define CHECK_AUTH(auth, ret) if (gnutls_auth_get_type(state) != auth) { \