From 34561b4f0546a8de113fabd802c2d2a292999640 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 29 Dec 2003 11:38:38 +0000 Subject: Added support for TLS 1.1 --- lib/gnutls.h.in.in | 5 ++-- lib/gnutls_algorithms.c | 1 + lib/gnutls_cipher.c | 67 ++++++++++++++++++++++++++++++++----------- lib/gnutls_int.h | 3 +- lib/gnutls_record.c | 75 ++++++------------------------------------------- lib/gnutls_state.c | 24 ---------------- 6 files changed, 63 insertions(+), 112 deletions(-) (limited to 'lib') diff --git a/lib/gnutls.h.in.in b/lib/gnutls.h.in.in index 4f60eafa17..05f38c3071 100644 --- a/lib/gnutls.h.in.in +++ b/lib/gnutls.h.in.in @@ -146,7 +146,8 @@ typedef enum gnutls_openpgp_key_status { GNUTLS_OPENPGP_KEY, typedef enum gnutls_close_request { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } gnutls_close_request; -typedef enum gnutls_protocol_version { GNUTLS_SSL3=1, GNUTLS_TLS1 } gnutls_protocol_version; +typedef enum gnutls_protocol_version { GNUTLS_SSL3=1, GNUTLS_TLS1, + GNUTLS_TLS1_1 } gnutls_protocol_version; typedef enum gnutls_certificate_type { GNUTLS_CRT_X509=1, GNUTLS_CRT_OPENPGP } gnutls_certificate_type; @@ -228,8 +229,6 @@ void gnutls_handshake_set_private_extensions(gnutls_session session, int allow); gnutls_handshake_description gnutls_handshake_get_last_out( gnutls_session session); gnutls_handshake_description gnutls_handshake_get_last_in( gnutls_session session); -void gnutls_record_set_cbc_protection(gnutls_session session, int prot); - /* Record layer functions. */ ssize_t gnutls_record_send( gnutls_session session, const void *data, size_t sizeofdata); diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c index 13e7e14c97..c02a308f36 100644 --- a/lib/gnutls_algorithms.c +++ b/lib/gnutls_algorithms.c @@ -106,6 +106,7 @@ typedef struct { static const gnutls_version_entry sup_versions[] = { {"SSL 3.0", GNUTLS_SSL3, 3, 0, 1}, {"TLS 1.0", GNUTLS_TLS1, 3, 1, 1}, + {"TLS 1.1", GNUTLS_TLS1_1, 3, 2, 1}, {0, 0, 0, 0, 0} }; diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c index b0ca7a2311..b5e58c7928 100644 --- a/lib/gnutls_cipher.c +++ b/lib/gnutls_cipher.c @@ -158,14 +158,16 @@ int _gnutls_decrypt(gnutls_session session, opaque *ciphertext, } inline -static GNUTLS_MAC_HANDLE mac_init( gnutls_mac_algorithm mac, opaque* secret, int secret_size, int ver) { +static GNUTLS_MAC_HANDLE +mac_init( gnutls_mac_algorithm mac, opaque* secret, int secret_size, int ver) +{ GNUTLS_MAC_HANDLE td; if ( ver == GNUTLS_SSL3) { /* SSL 3.0 */ td = _gnutls_mac_init_ssl3( mac, secret, secret_size); - } else { /* TLS 1 */ + } else { /* TLS 1.x */ td = _gnutls_hmac_init( mac, secret, secret_size); } @@ -174,7 +176,8 @@ GNUTLS_MAC_HANDLE td; } inline -static void mac_deinit( GNUTLS_MAC_HANDLE td, opaque* res, int ver) { +static void mac_deinit( GNUTLS_MAC_HANDLE td, opaque* res, int ver) +{ if ( ver == GNUTLS_SSL3) { /* SSL 3.0 */ _gnutls_mac_deinit_ssl3(td, res); } else { @@ -222,6 +225,8 @@ int length; *pad = (uint8) (blocksize - (length % blocksize)) + rand; length += *pad; + if ( session->security_parameters.version >= GNUTLS_TLS1_1) + length += blocksize; /* for the IV */ break; default: @@ -255,6 +260,7 @@ int _gnutls_compressed2ciphertext(gnutls_session session, _gnutls_cipher_get_block_size(session->security_parameters. write_bulk_cipher_algorithm); CipherType block_algo = _gnutls_cipher_is_block(session->security_parameters.write_bulk_cipher_algorithm); + opaque* data_ptr; ver = gnutls_protocol_get_version( session); @@ -279,7 +285,7 @@ int _gnutls_compressed2ciphertext(gnutls_session session, _gnutls_hmac(td, UINT64DATA(session->connection_state.write_sequence_number), 8); _gnutls_hmac(td, &type, 1); - if ( ver != GNUTLS_SSL3) { /* TLS 1.0 only */ + if ( ver >= GNUTLS_TLS1) { /* TLS 1.0 only */ _gnutls_hmac(td, &major, 1); _gnutls_hmac(td, &minor, 1); } @@ -305,11 +311,29 @@ int _gnutls_compressed2ciphertext(gnutls_session session, return GNUTLS_E_MEMORY_ERROR; } - 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); + data_ptr = cipher_data; + if ( block_algo==CIPHER_BLOCK && + session->security_parameters.version >= GNUTLS_TLS1_1) + { + /* copy the random IV. + */ + if (_gnutls_get_random(data_ptr, blocksize, GNUTLS_STRONG_RANDOM) < 0) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + data_ptr += blocksize; + } + + memcpy(data_ptr, compressed.data, compressed.size); + data_ptr += compressed.size; + + if (hash_size > 0) { + memcpy(data_ptr, MAC, hash_size); + data_ptr += hash_size; + } + if (block_algo==CIPHER_BLOCK && pad > 0) { + memset(data_ptr, pad - 1, pad); + } /* Actual encryption (inplace). @@ -390,13 +414,24 @@ int _gnutls_ciphertext2compressed(gnutls_session session, return ret; } + /* ignore the IV in TLS 1.1. + */ + if (session->security_parameters.version >= GNUTLS_TLS1_1) { + ciphertext.size -= blocksize; + ciphertext.data += blocksize; + + if (ciphertext.size == 0) { + gnutls_assert(); + return GNUTLS_E_DECRYPTION_FAILED; + } + } + pad = ciphertext.data[ciphertext.size - 1] + 1; /* pad */ length = ciphertext.size - hash_size - pad; - - if (pad > - ciphertext.size - hash_size) { + + if (pad > ciphertext.size - hash_size) { gnutls_assert(); /* We do not fail here. We check below for the * the pad_failed. If zero means success. @@ -404,14 +439,12 @@ int _gnutls_ciphertext2compressed(gnutls_session session, pad_failed = GNUTLS_E_DECRYPTION_FAILED; } - /* Check the pading bytes (TLS 1.0 only) + /* Check the pading bytes (TLS 1.x only) */ - if ( ver == GNUTLS_TLS1) + if ( ver >= GNUTLS_TLS1) for (i=2;iconnection_state.read_sequence_number), 8); _gnutls_hmac(td, &type, 1); - if ( ver != GNUTLS_SSL3) { /* TLS 1.0 only */ + if ( ver >= GNUTLS_TLS1) { /* TLS 1.0 only */ _gnutls_hmac(td, &major, 1); _gnutls_hmac(td, &minor, 1); } diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 7eb254f64a..63d6228318 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -298,7 +298,8 @@ typedef struct { /* Versions should be in order of the oldest * (eg. SSL3 is before TLS1) */ -typedef enum gnutls_protocol_version { GNUTLS_SSL3=1, GNUTLS_TLS1, GNUTLS_VERSION_UNKNOWN=0xff } +typedef enum gnutls_protocol_version { GNUTLS_SSL3=1, GNUTLS_TLS1, + GNUTLS_TLS1_1, GNUTLS_VERSION_UNKNOWN=0xff } gnutls_protocol_version; /* This structure holds parameters got from TLS extension diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index ccb6ae99d0..eb0c22028b 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -51,11 +51,13 @@ * Returns the version of the currently used protocol. * **/ -gnutls_protocol_version gnutls_protocol_get_version(gnutls_session session) { +gnutls_protocol_version gnutls_protocol_get_version(gnutls_session session) +{ return session->security_parameters.version; } -void _gnutls_set_current_version(gnutls_session session, gnutls_protocol_version version) { +void _gnutls_set_current_version(gnutls_session session, gnutls_protocol_version version) +{ session->security_parameters.version = version; } @@ -253,48 +255,6 @@ gnutls_protocol_version lver; } } -inline static -ssize_t _gnutls_create_empty_record( gnutls_session session, ContentType type, - opaque* erecord, unsigned int erecord_size) -{ - int cipher_size; - int retval; - int data2send; - uint8 headers[5]; - - if (type!=GNUTLS_APPLICATION_DATA || - _gnutls_cipher_is_block( gnutls_cipher_get(session))!=CIPHER_BLOCK) - /* alert messages and stream ciphers - * do not need this protection - */ - return 0; - - headers[0] = type; - - copy_record_version( session, (HandshakeType)(-1), &headers[1]); - - data2send = 0; - - cipher_size = _gnutls_encrypt( session, 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; - return cipher_size; /* error */ - } - - retval = cipher_size; - - /* increase sequence number - */ - if (_gnutls_uint64pp( &session->connection_state.write_sequence_number) != 0) { - _gnutls_session_invalidate( session); - gnutls_assert(); - return GNUTLS_E_RECORD_LIMIT_REACHED; - } - - return retval; -} - /* This function behaves exactly like write(). The only difference is * that it accepts, the gnutls_session and the ContentType of data to * send (if called by the user the Content is specific) @@ -368,27 +328,6 @@ ssize_t _gnutls_send_int( gnutls_session session, ContentType type, retval = session->internals.record_send_buffer_user_size; } else { - /* Prepend our packet with an empty record. This is to - * avoid the recent CBC attacks. - */ - /* if this protection has been disabled - */ - if (session->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( session, type, erecord, erecord_size); - if (erecord_size < 0) { - gnutls_assert(); - return erecord_size; - } - } - /* now proceed to packet encryption */ cipher_size = data2send_size + MAX_RECORD_OVERHEAD; @@ -563,10 +502,10 @@ static int _gnutls_check_record_headers( gnutls_session session, uint8 headers[R /* Here we check if the advertized version is the one we * negotiated in the handshake. */ +#ifdef CHECK_RECORD_VERSION inline static int _gnutls_check_record_version( gnutls_session session, HandshakeType htype, opaque version[2]) { -#ifdef CHECK_RECORD_VERSION if ( (htype!=GNUTLS_CLIENT_HELLO && htype!=GNUTLS_SERVER_HELLO) && gnutls_protocol_get_version(session) != _gnutls_version_get( version[0], version[1])) { @@ -576,10 +515,12 @@ static int _gnutls_check_record_version( gnutls_session session, HandshakeType h return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; } -#endif return 0; } +#else +# define _gnutls_check_record_version(x,y,z) 0 +#endif /* This function will check if the received record type is * the one we actually expect. diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index aa06c0fbe4..1ed1310df8 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -506,30 +506,6 @@ void _gnutls_record_set_default_version(gnutls_session session, session->internals.default_record_version[1] = minor; } -/** - * gnutls_record_set_cbc_protection - Used to disable the CBC protection - * @session: is a &gnutls_session structure. - * @prot: is an integer (0 or 1) - * - * A newly discovered attack against the record protocol requires some - * counter-measures to be taken. GnuTLS will not enable them by default. - * The protection is to send an empty record packet, before each actual record - * packet, in order to assure that the IV is not known to potential attackers. - * - * This function will enable or disable the chosen plaintext protection - * in the TLS record protocol (used with ciphers in CBC mode). - * if prot == 0 then protection is disabled (default), otherwise it - * is enabled. - * - * The protection used will slightly decrease performance, and add - * 20 or more bytes per record packet. - * - **/ -void gnutls_record_set_cbc_protection(gnutls_session session, int prot) -{ - session->internals.cbc_protection_hack = prot; -} - /** * gnutls_handshake_set_private_extensions - Used to enable the private cipher suites * @session: is a &gnutls_session structure. -- cgit v1.2.1