summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-12-29 11:38:38 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-12-29 11:38:38 +0000
commit34561b4f0546a8de113fabd802c2d2a292999640 (patch)
treed4af4a0b391e1a4f80de6852e64b2be1612ac8c1
parentfa49bb280c3226ef04055a35bbdb4b05f6a84181 (diff)
downloadgnutls-34561b4f0546a8de113fabd802c2d2a292999640.tar.gz
Added support for TLS 1.1
-rw-r--r--NEWS1
-rw-r--r--doc/tex/ex-cert-select.tex4
-rw-r--r--doc/tex/macros.tex1
-rw-r--r--doc/tex/record_weaknesses.tex12
-rw-r--r--lib/gnutls.h.in.in5
-rw-r--r--lib/gnutls_algorithms.c1
-rw-r--r--lib/gnutls_cipher.c67
-rw-r--r--lib/gnutls_int.h3
-rw-r--r--lib/gnutls_record.c75
-rw-r--r--lib/gnutls_state.c24
-rw-r--r--src/common.c5
-rw-r--r--src/serv.c2
12 files changed, 76 insertions, 124 deletions
diff --git a/NEWS b/NEWS
index b9c44e4076..5ec2089c63 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
Version 1.1.2 (28/12/2003)
- Added CRL verification functionality to certtool.
- Corrected the CRL distribution point extension handling.
+- Implemented TLS 1.1
Version 1.1.1 (26/12/2003)
- Added PKCS #7 support to certtool utility.
diff --git a/doc/tex/ex-cert-select.tex b/doc/tex/ex-cert-select.tex
index 2137bebb92..35b829c524 100644
--- a/doc/tex/ex-cert-select.tex
+++ b/doc/tex/ex-cert-select.tex
@@ -26,6 +26,7 @@
static int cert_callback(gnutls_session session,
const gnutls_datum* req_ca_rdn, int nreqs,
+ const gnutls_pk_algorithm* sign_algos, int sign_algos_length,
gnutls_retr_st * st);
gnutls_x509_crt crt;
@@ -192,6 +193,7 @@ int main()
static int cert_callback(gnutls_session session,
const gnutls_datum* req_ca_rdn, int nreqs,
+ const gnutls_pk_algorithm* sign_algos, int sign_algos_length,
gnutls_retr_st * st)
{
char issuer_dn[256];
@@ -217,6 +219,8 @@ static int cert_callback(gnutls_session session,
}
/* Select a certificate and return it.
+ * The certificate must be of any of the "sign algorithms"
+ * supported by the server.
*/
type = gnutls_certificate_type_get( session);
diff --git a/doc/tex/macros.tex b/doc/tex/macros.tex
index 060f4dfe26..550dcc05c5 100644
--- a/doc/tex/macros.tex
+++ b/doc/tex/macros.tex
@@ -1,6 +1,7 @@
\newcommand{\gnutls}{{\emph{GnuTLS}}}
\newcommand{\gnutlse}{{\emph{GnuTLS-extra}}}
\newcommand{\tlsI}{{\emph{TLS 1.0}}}
+\newcommand{\tlsII}{{\emph{TLS 1.1}}}
\newcommand{\tls}{{\emph{TLS}}}
\newcommand{\sslIII}{{\emph{SSL 3.0}}}
\newcommand{\sslII}{{\emph{SSL 2.0}}}
diff --git a/doc/tex/record_weaknesses.tex b/doc/tex/record_weaknesses.tex
index e04f790475..21845dd1e1 100644
--- a/doc/tex/record_weaknesses.tex
+++ b/doc/tex/record_weaknesses.tex
@@ -10,15 +10,7 @@ and exploit the facts that
\item the IV for CBC encrypted packets is the last block of the previous encrypted packet
\end{enumerate}
-\gnutls{} implements all the known counter-measures for these attacks. For the first
-two cases, \gnutls{} does only have one error code for both of the decryption failures,
-and processes the message normally even if a padding error occured. This avoids
-both of these attacks.
-For the latter, an empty record can be sent before every record packet, and this is
-believed to avoid the known attacks in CBC encrypted packets. See the function
-\printfunc{gnutls_record_set_cbc_protection}{gnutls\_record\_set\_cbc\_protection}
-for more information.
-
-For a detailed discussion see the archives of the TLS Working Group mailing list
+Those weaknesses were solved in \tlsII{} which is implemented in
+\gnutls{}. For a detailed discussion see the archives of the TLS Working Group mailing list
and the paper \cite{CBCATT}.
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;i<pad;i++) {
if (ciphertext.data[ciphertext.size-i] != ciphertext.data[ciphertext.size - 1])
- {
pad_failed = GNUTLS_E_DECRYPTION_FAILED;
- }
}
break;
@@ -430,7 +463,7 @@ int _gnutls_ciphertext2compressed(gnutls_session session,
_gnutls_hmac(td, UINT64DATA(session->connection_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
@@ -507,30 +507,6 @@ void _gnutls_record_set_default_version(gnutls_session session,
}
/**
- * 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.
* @allow: is an integer (0 or 1)
diff --git a/src/common.c b/src/common.c
index b0e7a15e39..839289fdc9 100644
--- a/src/common.c
+++ b/src/common.c
@@ -479,6 +479,7 @@ void print_list(void)
printf("Protocols:");
printf(" TLS1.0");
+ printf(", TLS1.1");
printf(", SSL3.0\n");
printf("Ciphers:");
@@ -534,7 +535,9 @@ void parse_protocols(char **protocols, int protocols_size,
for (j = i = 0; i < protocols_size; i++) {
if (strncasecmp(protocols[i], "SSL", 3) == 0)
protocol_priority[j++] = GNUTLS_SSL3;
- if (strncasecmp(protocols[i], "TLS", 3) == 0)
+ if (strncasecmp(protocols[i], "TLS1.1", 6) == 0)
+ protocol_priority[j++] = GNUTLS_TLS1_1;
+ if (strncasecmp(protocols[i], "TLS1.0", 6) == 0)
protocol_priority[j++] = GNUTLS_TLS1;
}
protocol_priority[j] = 0;
diff --git a/src/serv.c b/src/serv.c
index 561e47664b..2a96f2a256 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -248,7 +248,7 @@ static int generate_rsa_params(void)
return 0;
}
-int protocol_priority[PRI_MAX] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
+int protocol_priority[PRI_MAX] = { GNUTLS_TLS1_1, GNUTLS_TLS1, GNUTLS_SSL3, 0 };
int kx_priority[PRI_MAX] =
{ GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP,
/* Do not use anonymous authentication, unless you know what that means */