Introduction to TLS and DTLS
****************************

TLS stands for ``Transport Layer Security'' and is the successor of SSL, the Secure Sockets Layer protocol SSL3 designed by Netscape.  TLS is an Internet protocol, defined by IETF (IETF, or Internet Engineering Task Force, is a large open international community of network designers, operators, vendors, and researchers concerned with the evolution of the Internet architecture and the smooth operation of the Internet. It is open to any interested individual.), described in RFC5246. The protocol provides confidentiality, and authentication layers over any reliable transport layer.  The description, below, refers to TLS 1.0 but also applies to TLS 1.2 RFC5246 and SSL 3.0, since the differences of these protocols are not major.

The DTLS protocol, or ``Datagram TLS'' RFC4347 is a protocol with identical goals as TLS, but can operate under unreliable transport layers, such as UDP. The discussions below apply to this protocol as well, except when noted otherwise.

TLS layers
==========

TLS is a layered protocol, and consists of the record protocol, the handshake protocol and the alert protocol. The record protocol is to serve all other protocols and is above the transport layer.  The record protocol offers symmetric encryption, data authenticity, and optionally compression. The alert protocol offers some signaling to the other protocols. It can help informing the peer for the cause of failures and other error conditions.  See The Alert Protocol, for more information.  The alert protocol is above the record protocol.

The handshake protocol is responsible for the security parameters' negotiation, the initial key exchange and authentication. See The Handshake Protocol, for more information about the handshake protocol.  The protocol layering in TLS is shown in fig:tls-layers.

Figure: The TLS protocol layers.

The transport layer
===================

TLS is not limited to any transport layer and can be used above any transport layer, as long as it is a reliable one.  DTLS can be used over reliable and unreliable transport layers. GnuTLS supports TCP and UDP layers transparently using the Berkeley sockets API. However, any transport layer can be used by providing callbacks for GnuTLS to access the transport layer (for details see TLS and DTLS sessions).

The TLS record protocol
=======================

The record protocol is the secure communications provider. Its purpose is to encrypt, authenticate and ---optionally--- compress packets.

gnutls_record_send

The record layer functions can be called at any time after the handshake process is finished, when there is need to receive or send data. In DTLS however, due to re-transmission timers used in the handshake out-of-order handshake data might be received for some time (maximum 60 seconds) after the handshake process is finished. For this reason programs using DTLS should call gnutls_record_recv or gnutls_record_recv_seq for every packet received by the peer, even if no data were expected.

As you may have already noticed, the functions which access the record protocol, are quite limited, given the importance of this protocol in TLS.  This is because the record protocol's parameters are all set by the handshake protocol.

The record protocol initially starts with NULL parameters, which means no encryption, and no MAC is used. Encryption and authentication begin just after the handshake protocol has finished.

gnutls_record_recv,gnutls_record_recv_seq,gnutls_record_check_pending,gnutls_record_get_direction

Encryption algorithms used in the record layer
----------------------------------------------

Confidentiality in the record layer is achieved by using symmetric block encryption algorithms like 3DES, AES or stream algorithms like ARCFOUR_128. Ciphers are encryption algorithms that use a single, secret, key to encrypt and decrypt data. Block algorithms in TLS also provide protection against statistical analysis of the data.  Thus, if you're using the TLS protocol, a random number of blocks will be appended to data, to prevent eavesdroppers from guessing the actual data size.

The supported in GnuTLS ciphers and MAC algorithms are shown in tab:ciphers and tab:macs.

Algorithm   Description
3DES_CBC
This is the DES block cipher algorithm used with triple
encryption (EDE). Has 64 bits block size and is used in CBC mode.

ARCFOUR_128
ARCFOUR_128 is a compatible algorithm with RSA's RC4 algorithm, which is considered to be a trade
secret. It is a fast cipher but considered weak today.

ARCFOUR_40
This is the ARCFOUR cipher fed with a 40 bit key,
which is considered weak.

AES_CBC
AES or RIJNDAEL is the block cipher algorithm that replaces the old
DES algorithm.  Has 128 bits block size and is used in CBC mode.

AES_GCM
This is the AES algorithm in the authenticated encryption GCM mode.
This mode combines message authentication and encryption and can
be extremely fast on CPUs that support hardware acceleration.

CAMELLIA_CBC
This is an 128-bit block cipher developed by Mitsubishi and NTT. It
is one of the approved ciphers of the European NESSIE and Japanese
CRYPTREC projects.

Table: Supported ciphers.

Algorithm   Description
MAC_MD5
This is a cryptographic hash algorithm designed by Ron Rivest. Outputs
128 bits of data.

MAC_SHA1
A cryptographic hash algorithm designed by NSA. Outputs 160
bits of data.

MAC_SHA256
A cryptographic hash algorithm designed by NSA. Outputs 256
bits of data.

MAC_AEAD
This indicates that an authenticated encryption algorithm, such as
GCM, is in use.

Table: Supported MAC algorithms.

Compression algorithms used in the record layer
-----------------------------------------------

The TLS record layer also supports compression.  The algorithms implemented in GnuTLS can be found in the table below. The included algorithms perform really good when text, or other compressible data are to be transferred, but offer nothing on already compressed data, such as compressed images, zipped archives etc. These compression algorithms, may be useful in high bandwidth TLS tunnels, and in cases where network usage has to be minimized. It should be noted however that compression increases latency.

The record layer compression in GnuTLS is implemented based on the proposal RFC3749. The supported algorithms are:

DEFLATE:
     Zlib compression, using the deflate algorithm.

NULL:
     No compression.

Weaknesses and countermeasures
------------------------------

Some weaknesses that may affect the security of the record layer have been found in TLS 1.0 protocol. These weaknesses can be exploited by active attackers, and exploit the facts that

 1. TLS has separate alerts for ``decryption_failed'' and ``bad_record_mac''

 2. The decryption failure reason can be detected by timing the response time.

 3. The IV for CBC encrypted packets is the last block of the previous encrypted packet.

Those weaknesses were solved in TLS 1.1 RFC4346 which is implemented in GnuTLS. For a detailed discussion see the archives of the TLS Working Group mailing list and CBCATT.

On record padding
-----------------

The TLS protocol allows for random padding of records, to prevent statistical analysis based on the length of exchanged messages (see RFC5246 section 6.2.3.2). GnuTLS appears to be one of few implementation that take advantage of this text, and pad records by a random length.

The TLS implementation in the Symbian operating system, frequently used by Nokia and Sony-Ericsson mobile phones, cannot handle non-minimal record padding.  What happens when one of these clients handshake with a GnuTLS server is that the client will fail to compute the correct MAC for the record.  The client sends a TLS alert (bad_record_mac) and disconnects.  Typically this will result in error messages such as 'A TLS fatal alert has been received', 'Bad record MAC', or both, on the GnuTLS server side.

GnuTLS implements a work around for this problem.  However, it has to be enabled specifically.  It can be enabled by using gnutls_record_disable_padding, or gnutls_priority_set with the %COMPAT priority string (see Priority Strings).

If you implement an application that have a configuration file, we recommend that you make it possible for users or administrators to specify a GnuTLS protocol priority string, which is used by your application via gnutls_priority_set.  To allow the best flexibility, make it possible to have a different priority string for different incoming IP addresses.

The TLS alert protocol
======================

The alert protocol is there to allow signals to be sent between peers. These signals are mostly used to inform the peer about the cause of a protocol failure. Some of these signals are used internally by the protocol and the application protocol does not have to cope with them (e.g. GNUTLS_A_CLOSE_NOTIFY), and others refer to the application protocol solely (e.g. GNUTLS_A_USER_CANCELLED).  An alert signal includes a level indication which may be either fatal or warning. Fatal alerts always terminate the current connection, and prevent future re-negotiations using the current session ID. All alert messages are summarized in tab:alerts.

The alert messages are protected by the record protocol, thus the information that is included does not leak. You must take extreme care for the alert information not to leak to a possible attacker, via public log files etc. The available functions to control the alert protocol are shown below.

gnutls_alert_get

gnutls_alert_send

gnutls_error_to_alert,gnutls_alert_get_name

     [file alerts.texi not included]

The TLS handshake protocol
==========================

The handshake protocol is responsible for the ciphersuite negotiation, the initial key exchange, and the authentication of the two peers. This is fully controlled by the application layer, thus your program has to set up the required parameters. The main handshake function is gnutls_handshake. In the next paragraphs we elaborate on the handshake protocol, i.e., the ciphersuite negotiation.

TLS ciphersuites
----------------

The handshake protocol of TLS negotiates cipher suites of a special form illustrated by the TLS_DHE_RSA_WITH_3DES_CBC_SHA cipher suite name.  A typical cipher suite contains these parameters:

  * The key exchange algorithm. DHE_RSA in the example.

  * The Symmetric encryption algorithm and mode 3DES_CBC in this example.

  * The MAC (MAC stands for Message Authentication Code. It can be described as a keyed hash algorithm. See RFC2104.) algorithm used for authentication. MAC_SHA is used in the above example.

The cipher suite negotiated in the handshake protocol will affect the record protocol, by enabling encryption and data authentication.  Note that you should not over rely on TLS to negotiate the strongest available cipher suite. Do not enable ciphers and algorithms that you consider weak.

All the supported ciphersuites are listed in ciphersuites.

Client authentication
---------------------

In the case of ciphersuites that use certificate authentication, the authentication of the client is optional in TLS.  A server may request a certificate from the client using the gnutls_certificate_server_set_request function. If a certificate is to be requested from the client during the handshake, the server will send a certificate request message that contains a list of acceptable certificate signers. In GnuTLS the certificate signers list is constructed using the trusted Certificate Authorities by the server. That is the ones set using the following functions.

gnutls_certificate_set_x509_trust_file,gnutls_certificate_set_x509_trust_mem

gnutls_certificate_server_set_request

In cases where the server supports a large number of certificate authorities it makes sense not to advertise all of the names to save bandwidth. That can be controlled using the function gnutls_certificate_send_x509_rdn_sequence. This however will have the side-effect of not restricting the client to certificates signed by server's acceptable signers.

gnutls_certificate_send_x509_rdn_sequence

Resuming sessions
-----------------

The gnutls_handshake function, is expensive since a lot of calculations are performed. In order to support many fast connections to the same server a client may use session resuming. Session resuming is a feature of the TLS protocol which allows a client to connect to a server, after a successful handshake, without the expensive calculations.  This is achieved by re-using the previously established keys. GnuTLS supports this feature, and the example in ex:resume-client illustrates a typical use of it.

Keep in mind that sessions might be expired after some time, thus it may be normal for a server not to resume a session even if you requested that.  That is to prevent temporal session keys from becoming long-term keys. Also note that as a client you must enable, using the priority functions, at least the algorithms used in the last session.

The resuming capability, mostly in the server side, is one of the problems of a thread-safe TLS implementations. The problem is that all threads must share information in order to be able to resume sessions. The gnutls approach is, in case of a client, to leave all the burden of resuming to the client. That is, copy and keep the necessary parameters. The relevant functions are listed below.

gnutls_session_get_data

gnutls_session_get_id

gnutls_session_set_data

Server side is different. A server needs to specify callback functions which store, retrieve and delete session data. These can be registered with the functions shown below.

gnutls_db_set_retrieve_function

gnutls_db_set_store_function

gnutls_db_set_ptr,gnutls_db_set_remove_function

It might also be useful to be able to check for expired sessions in order to remove them, and save space. The function gnutls_db_check_entry is provided for that reason.

gnutls_db_check_entry

Interoperability
----------------

The TLS handshake is a complex procedure that negotiates all required parameters for a secure session. GnuTLS supports several TLS extensions, as well as the latest TLS protocol version 1.2. However few implementations are not able to properly interoperate once faced with extensions or version protocols they do not support and understand. The TLS protocol allows for a graceful downgrade to the commonly supported options, but practice shows it is not always implemented correctly.

Because there is no way to achieve maximum interoperability with broken peers without sacrificing security, GnuTLS ignores such peers by default. This might not be acceptable in cases where maximum compatibility is required. Thus we allow enabling compatibility with broken peers using priority strings (see Priority Strings). An example priority string that is known to provide wide compatibility even with broken peers is shown below:
NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0:+VERS-SSL3.0:%COMPAT
This priority string will only enable SSL 3.0 and TLS 1.0 as protocols and will disable, via the %COMPAT keyword, several TLS protocol options that are known to cause compatibility problems. We suggest however only to use this mode if compatibility is preferred over security.

TLS extensions
==============

A number of extensions to the TLS protocol have been proposed mainly in TLSEXT. The extensions supported in GnuTLS are:

  * Maximum fragment length negotiation

  * Server name indication

  * Session tickets

  * Safe Renegotiation

and they will be discussed in the subsections that follow.

Maximum fragment length negotiation
-----------------------------------

This extension allows a TLS implementation to negotiate a smaller value for record packet maximum length. This extension may be useful to clients with constrained capabilities. The functions shown below can be used to control this extension.

gnutls_record_get_max_size

gnutls_record_set_max_size

Server name indication
----------------------

A common problem in HTTPS servers is the fact that the TLS protocol is not aware of the hostname that a client connects to, when the handshake procedure begins. For that reason the TLS server has no way to know which certificate to send.

This extension solves that problem within the TLS protocol, and allows a client to send the HTTP hostname before the handshake begins within the first handshake packet.  The functions gnutls_server_name_set and gnutls_server_name_get can be used to enable this extension, or to retrieve the name sent by a client.

gnutls_server_name_set

gnutls_server_name_get

Session tickets
---------------

To resume a TLS session the server normally store some state.  This complicates deployment, and typical situations the client can cache information and send it to the server instead.  The Session Ticket extension implements this idea, and it is documented in RFC 5077 TLSTKT.

Clients can enable support for TLS tickets with gnutls_session_ticket_enable_client and servers use gnutls_session_ticket_key_generate to generate a key and gnutls_session_ticket_enable_server to enable the extension. Clients resume sessions using the ticket using the normal session resume functions, resume.

gnutls_session_ticket_key_generate

gnutls_session_ticket_enable_server

gnutls_session_ticket_enable_client

Safe renegotiation
------------------

TLS gives the option to two communicating parties to renegotiate and update their security parameters. One useful example of this feature was for a client to initially connect using anonymous negotiation to a server, and the renegotiate using some authenticated ciphersuite. This occurred to avoid having the client sending its credentials in the clear.

However this renegotiation, as initially designed would not ensure that the party one is renegotiating is the same as the one in the initial negotiation. For example one server could forward all renegotiation traffic to an other server who will see this traffic as an initial negotiation attempt.

This might be seen as a valid design decision, but it seems it was not widely known or understood, thus today some application protocols the TLS renegotiation feature in a manner that enables a malicious server to insert content of his choice in the beginning of a TLS session.

The most prominent vulnerability was with HTTPS. There servers request a renegotiation to enforce an anonymous user to use a certificate in order to access certain parts of a web site.  The attack works by having the attacker simulate a client and connect to a server, with server-only authentication, and send some data intended to cause harm.  The server will then require renegotiation from him in order to perform the request. When the proper client attempts to contact the server, the attacker hijacks that connection and forwards traffic to the initial server that requested renegotiation.  The attacker will not be able to read the data exchanged between the client and the server.  However, the server will (incorrectly) assume that the initial request sent by the attacker was sent by the now authenticated client.  The result is a prefix plain-text injection attack.

The above is just one example.  Other vulnerabilities exists that do not rely on the TLS renegotiation to change the client's authenticated status (either TLS or application layer).

While fixing these application protocols and implementations would be one natural reaction, an extension to TLS has been designed that cryptographically binds together any renegotiated handshakes with the initial negotiation.  When the extension is used, the attack is detected and the session can be terminated.  The extension is specified in RFC5746.

GnuTLS supports the safe renegotiation extension.  The default behavior is as follows.  Clients will attempt to negotiate the safe renegotiation extension when talking to servers.  Servers will accept the extension when presented by clients.  Clients and servers will permit an initial handshake to complete even when the other side does not support the safe renegotiation extension.  Clients and servers will refuse renegotiation attempts when the extension has not been negotiated.

Note that permitting clients to connect to servers when the safe renegotiation extension is not enabled, is open up for attacks. Changing this default behavior would prevent interoperability against the majority of deployed servers out there.  We will reconsider this default behavior in the future when more servers have been upgraded. Note that it is easy to configure clients to always require the safe renegotiation extension from servers.

To modify the default behavior, we have introduced some new priority strings (see Priority Strings). The %UNSAFE_RENEGOTIATION priority string permits (re-)handshakes even when the safe renegotiation extension was not negotiated. The default behavior is %PARTIAL_RENEGOTIATION that will prevent renegotiation with clients and servers not supporting the extension. This is secure for servers but leaves clients vulnerable to some attacks, but this is a trade-off between security and compatibility with old servers. The %SAFE_RENEGOTIATION priority string makes clients and servers require the extension for every handshake. The latter is the most secure option for clients, at the cost of not being able to connect to legacy servers. Servers will also deny clients that do not support the extension from connecting.

It is possible to disable use of the extension completely, in both clients and servers, by using the %DISABLE_SAFE_RENEGOTIATION priority string however we strongly recommend you to only do this for debugging and test purposes.

The default values if the flags above are not specified are:

Server:
     %PARTIAL_RENEGOTIATION

Client:
     %PARTIAL_RENEGOTIATION

For applications we have introduced a new API related to safe renegotiation.  The gnutls_safe_renegotiation_status function is used to check if the extension has been negotiated on a session, and can be used both by clients and servers.

Selecting cryptographic key sizes
=================================

Because many algorithms are involved in TLS, it is not easy to set a consistent security level.  For this reason in tab:key-sizes we present some correspondence between key sizes of symmetric algorithms and public key algorithms based on ECRYPT. Those can be used to generate certificates with appropriate key sizes as well as select parameters for Diffie-Hellman and SRP authentication.

Security bits   RSA, DH and SRP parameter size   ECC key size   Security parameter   Description

64
816
128
WEAK
Very short term protection against small organizations

80
1248
160
LOW
Very short term protection against agencies

112
2432
224
NORMAL
Medium-term protection

128
3248
256
HIGH
Long term protection

256
15424
512
ULTRA
Foreseeable future

Table: Key sizes and security parameters.

The first column  provides a security parameter in a number of bits. This gives an indication of the number of combinations to be tried by an adversary to brute force a key. For example to test all possible keys in a 112 bit security parameter 2^112 combinations have to be tried. For today's technology this is infeasible. The next two columns correlate the security parameter with actual bit sizes of parameters for DH, RSA, SRP and ECC algorithms. A mapping to gnutls_sec_param_t value is given for each security parameter, on the next column, and finally a brief description of the level.

Note, however, that the values suggested here are nothing more than an educated guess that is valid today. There are no guarantees that an algorithm will remain unbreakable or that these values will remain constant in time. There could be scientific breakthroughs that cannot be predicted or total failure of the current public key systems by quantum computers. On the other hand though the cryptosystems used in TLS are selected in a conservative way and such catastrophic breakthroughs or failures are believed to be unlikely. The NIST publication SP 800-57 NISTSP80057 contains a similar table.

When using GnuTLS and a decision on bit sizes for a public key algorithm is required, use of the following functions is recommended:

gnutls_sec_param_to_pk_bits

gnutls_pk_bits_to_sec_param

Those functions will convert a human understandable security parameter of gnutls_sec_param_t type, to a number of bits suitable for a public key algorithm.

On SSL 2 and older protocols
============================

One of the initial decisions in the GnuTLS development was to implement the known security protocols for the transport layer. Initially TLS 1.0 was implemented since it was the latest at that time, and was considered to be the most advanced in security properties.  Later the SSL 3.0 protocol was implemented since it is still the only protocol supported by several servers and there are no serious security vulnerabilities known.

One question that may arise is why we didn't implement SSL 2.0 in the library.  There are several reasons, most important being that it has serious security flaws, unacceptable for a modern security library.  Other than that, this protocol is barely used by anyone these days since it has been deprecated since 1996.  The security problems in SSL 2.0 include:

  * Message integrity compromised. The SSLv2 message authentication uses the MD5 function, and is insecure.

  * Man-in-the-middle attack. There is no protection of the handshake in SSLv2, which permits a man-in-the-middle attack.

  * Truncation attack. SSLv2 relies on TCP FIN to close the session, so the attacker can forge a TCP FIN, and the peer cannot tell if it was a legitimate end of data or not.

  * Weak message integrity for export ciphers. The cryptographic keys in SSLv2 are used for both message authentication and encryption, so if weak encryption schemes are negotiated (say 40-bit keys) the message authentication code use the same weak key, which isn't necessary.

Other protocols such as Microsoft's PCT 1 and PCT 2 were not implemented because they were also abandoned and deprecated by SSL 3.0 and later TLS 1.0.