How to use GnuTLS in applications
*********************************

Introduction
============

This chapter tries to explain the basic functionality of the current GnuTLS library. Note that there may be additional functionality not discussed here but included in the library. Checking the header files in /usr/include/gnutls/ and the manpages is recommended.

General idea
------------

A brief description of how GnuTLS sessions operate is shown at fig-gnutls-design. This section will become more clear when it is completely read. As shown in the figure, there is a read-only global state that is initialized once by the global initialization function.  This global structure, among others, contains the memory allocation functions used, structures needed for the ASN.1 parser and depending on the system's CPU, pointers to hardware accelerated encryption functions.  This structure is never modified by any GnuTLS function, except for the deinitialization function which frees all allocated memory and must be called after the program has permanently finished using GnuTLS.

Figure: High level design of GnuTLS.

The credentials structures are used by the authentication methods, such as certificate authentication. They store certificates, privates keys, and other information that is needed to prove the identity to the peer, and/or verify the identity of the peer. The information stored in the credentials structures is initialized once and then can be shared by many TLS sessions.

A GnuTLS session contains all the required state and information to handle one secure connection. The session communicates with the peers using the provided functions of the transport layer. Every session has a unique session ID shared with the peer.

Since TLS sessions can be resumed, servers need a database back-end to hold the session's parameters.  Every GnuTLS session after a successful handshake calls the appropriate back-end function (see resume) to store the newly negotiated session. The session database is examined by the server just after having received the client hello (The first message in a TLS handshake), and if the session ID sent by the client, matches a stored session, the stored session will be retrieved, and the new session will be a resumed one, and will share the same session ID with the previous one.

Error handling
--------------

There two types of GnuTLS functions. The first type returns a boolean value, true (non-zero) or false (zero) value; these functions are defined to return an unsigned integer type. The other type returns a signed integer type with zero (or a positive number) indicating success and a negative value indicating failure. For the latter type it is recommended to check for errors as following.

         ret = gnutls_function();
         if (ret < 0) {
             return -1;
         }

The above example checks for a failure condition rather than for explicit success (e.g., equality to zero). That has the advantage that future extensions of the API can be extended to provide additional information via positive returned values (see for example gnutls_certificate_set_x509_key_file).

In GnuTLS, many objects are represented as opaque types that are initialized by passing an address to storage of that type to a pointer parameter of a function name gnutls_OBJ_init, and which have a counterpart function gnutls_OBJ_deinit.  It is safe, but not mandatory, to pre-initialize the opaque storage to contain all zeroes (such as by using calloc() or memset()).  If the initializer succeeds, the storage must be passed to the counterpart deinitializer when the object is no longer in use to avoid memory leaks.  As of version 3.8.0, if the initializer function fails, it is safe, but not mandatory, to call the counterpart deinitializer, regardless of whether the storage was pre-initialized. However, this was not guaranteed in earlier versions; for maximum portability to older library versions, callers should either pre-initialize the storage to zero before initialization or refrain from calling the deinitializer if the initializer fails.

For certain operations such as TLS handshake and TLS packet receive there is the notion of fatal and non-fatal error codes. Fatal errors terminate the TLS session immediately and further sends and receives will be disallowed.  Such an example is GNUTLS_E_DECRYPTION_FAILED. Non-fatal errors may warn about something, i.e., a warning alert was received, or indicate the some action has to be taken. This is the case with the error code GNUTLS_E_REHANDSHAKE returned by gnutls_record_recv. This error code indicates that the server requests a re-handshake. The client may ignore this request, or may reply with an alert.  You can test if an error code is a fatal one by using the gnutls_error_is_fatal. All errors can be converted to a descriptive string using gnutls_strerror.

If any non fatal errors, that require an action, are to be returned by a function, these error codes will be documented in the function's reference. For example the error codes GNUTLS_E_WARNING_ALERT_RECEIVED and GNUTLS_E_FATAL_ALERT_RECEIVED that may returned when receiving data, should be handled by notifying the user of the alert (as explained in Handling alerts). See Error codes, for a description of the available error codes.

Common types
------------

All strings that are to provided as input to GnuTLS functions should be in UTF-8 unless otherwise specified. Output strings are also in UTF-8 format unless otherwise specified. When functions take as input passwords, they will normalize them using RFC7613 rules (since GnuTLS 3.5.7).

When data of a fixed size are provided to GnuTLS functions then the helper structure gnutls_datum_t is often used. Its definition is shown below.
  typedef struct
  {
    unsigned char *data;
    unsigned int size;
  } gnutls_datum_t;

In functions where this structure is a returned type, if the function succeeds, it is expected from the caller to use gnutls_free() to deinitialize the data element after use, unless otherwise specified. If the function fails, the contents of the gnutls_datum_t should be considered undefined and must not be deinitialized.

Other functions that require data for scattered read use a structure similar to struct iovec typically used by readv. It is shown below.
  typedef struct
  {
    void *iov_base;             /* Starting address */
    size_t iov_len;             /* Number of bytes to transfer */
  } giovec_t;

Debugging and auditing
----------------------

In many cases things may not go as expected and further information, to assist debugging, from GnuTLS is desired. Those are the cases where the gnutls_global_set_log_level and gnutls_global_set_log_function are to be used. Those will print verbose information on the GnuTLS functions internal flow.

gnutls_global_set_log_level,gnutls_global_set_log_function

Alternatively the environment variable GNUTLS_DEBUG_LEVEL can be set to a logging level and GnuTLS will output debugging output to standard error. Other available environment variables are shown in tab:environment.

Variable   Purpose

GNUTLS_DEBUG_LEVEL
When set to a numeric value, it sets the default debugging level for GnuTLS applications.

SSLKEYLOGFILE
When set to a filename, GnuTLS will append to it the session keys in the NSS Key Log
format. That format can be read by wireshark and will allow decryption of the session for debugging.

GNUTLS_CPUID_OVERRIDE
That environment variable can be used to
explicitly enable/disable the use of certain CPU capabilities. Note that CPU
detection cannot be overridden, i.e., VIA options cannot be enabled on an Intel
CPU. The currently available options are:

  * 0x1: Disable all run-time detected optimizations

  * 0x2: Enable AES-NI

  * 0x4: Enable SSSE3

  * 0x8: Enable PCLMUL

  * 0x10: Enable AVX

  * 0x20: Enable SHA_NI

  * 0x100000: Enable VIA padlock

  * 0x200000: Enable VIA PHE

  * 0x400000: Enable VIA PHE SHA512

GNUTLS_FORCE_FIPS_MODE
In setups where GnuTLS is compiled with support for FIPS140-2 (see FIPS140-2 mode)
if set to one it will force the FIPS mode enablement.

Table: Environment variables used by the library.

When debugging is not required, important issues, such as detected attacks on the protocol still need to be logged. This is provided by the logging function set by gnutls_global_set_audit_log_function. The provided function will receive an message and the corresponding TLS session. The session information might be used to derive IP addresses or other information about the peer involved.

gnutls_global_set_audit_log_function

Thread safety
-------------

The GnuTLS library is thread safe by design, meaning that objects of the library such as TLS sessions, can be safely divided across threads as long as a single thread accesses a single object. This is sufficient to support a server which handles several sessions per thread. Read-only access to objects, for example the credentials holding structures, is also thread-safe.

A gnutls_session_t object could also be shared by two threads, one sending, the other receiving. However, care must be taken on the following use cases:

  * The re-handshake process in TLS 1.2 or earlier must be handled only in a single thread and no other thread may be performing any operation.

  * The flag GNUTLS_AUTO_REAUTH cannot be used safely in this mode of operation.

  * Any other operation which may send or receive data, like key update (c.f., gnutls_session_key_update), must not be performed while threads are receiving or writing.

  * The termination of a session should be handled, either by a single thread being active, or by the sender thread using gnutls_bye with GNUTLS_SHUT_WR and the receiving thread waiting for a return value of zero (or timeout on certain servers which do not respond).

  * The functions gnutls_transport_set_errno and gnutls_record_get_direction should not be relied during parallel operation.

For several aspects of the library (e.g., the random generator, PKCS#11 operations), the library may utilize mutex locks (e.g., pthreads on GNU/Linux and CriticalSection on Windows) which are transparently setup on library initialization. Prior to version 3.3.0 these were setup by explicitly calling gnutls_global_init. (On special systems you could manually specify the locking system using the function gnutls_global_set_mutex before calling any other GnuTLS function. Setting mutexes manually is not recommended.)

Note that, on Glibc systems, unless the application is explicitly linked with the libpthread library, no mutex locks are used and setup by GnuTLS. It will use the Glibc mutex stubs.

Running in a sandbox
--------------------

Given that TLS protocol handling as well as X.509 certificate parsing are complicated processes involving several thousands lines of code, it is often desirable (and recommended) to run the TLS session handling in a sandbox like seccomp. That has to be allowed by the overall software design, but if available, it adds an additional layer of protection by preventing parsing errors from becoming vessels for further security issues such as code execution.

GnuTLS requires the following system calls to be available for its proper operation.

  * nanosleep

  * time

  * gettimeofday

  * clock_gettime

  * getrusage

  * getpid

  * send

  * recv

  * sendmsg

  * read (to read from /dev/urandom)

  * getrandom (this is Linux-kernel specific)

  * poll

As well as any calls needed for memory allocation to work. Note however, that GnuTLS depends on libc for the system calls, and there is no guarantee that libc will call the expected system call. For that it is recommended to test your program in all the targeted platforms when filters like seccomp are in place.

An example with a seccomp filter from GnuTLS' test suite is at: https://gitlab.com/gnutls/gnutls/blob/master/tests/seccomp.c.

Sessions and fork
-----------------

A gnutls_session_t object can be shared by two processes after a fork, one sending, the other receiving. In that case rehandshakes, cannot and must not be performed. As with threads, the termination of a session should be handled by the sender process using gnutls_bye with GNUTLS_SHUT_WR and the receiving process waiting for a return value of zero.

Callback functions
------------------

There are several cases where GnuTLS may need out of band input from your program. This is now implemented using some callback functions, which your program is expected to register.

An example of this type of functions are the push and pull callbacks which are used to specify the functions that will retrieve and send data to the transport layer.

gnutls_transport_set_push_function,gnutls_transport_set_pull_function

Other callback functions may require more complicated input and data to be allocated. Such an example is gnutls_srp_set_server_credentials_function. All callbacks should allocate and free memory using gnutls_malloc and gnutls_free.

Preparation
===========

To use GnuTLS, you have to perform some changes to your sources and your build system. The necessary changes are explained in the following subsections.

Headers
-------

All the data types and functions of the GnuTLS library are defined in the header file gnutls/gnutls.h.  This must be included in all programs that make use of the GnuTLS library.

Initialization
--------------

The GnuTLS library is initialized on load; prior to 3.3.0 was initialized by calling gnutls_global_init (The original behavior of requiring explicit initialization can obtained by setting the GNUTLS_NO_IMPLICIT_INIT environment variable to 1, or by using the macro GNUTLS_SKIP_GLOBAL_INIT in a global section of your program --the latter works in systems with support for weak symbols only.). gnutls_global_init in versions after 3.3.0 is thread-safe (see Thread safety).

The initialization typically enables CPU-specific acceleration, performs any required precalculations needed, opens any required system devices (e.g., /dev/urandom on Linux) and initializes subsystems that could be used later.

The resources allocated by the initialization process will be released on library deinitialization.

Note that on certain systems file descriptors may be kept open by GnuTLS (e.g. /dev/urandom) on library load. Applications closing all unknown file descriptors must immediately call gnutls_global_init, after that, to ensure they don't disrupt GnuTLS' operation.

Version check
-------------

It is often desirable to check that the version of `gnutls' used is indeed one which fits all requirements.  Even with binary compatibility new features may have been introduced but due to problem with the dynamic linker an old version is actually used.  So you may want to check that the version is okay right after program start-up. See the function gnutls_check_version.

On the other hand, it is often desirable to support more than one versions of the library. In that case you could utilize compile-time feature checks using the GNUTLS_VERSION_NUMBER macro. For example, to conditionally add code for GnuTLS 3.2.1 or later, you may use:

     #if GNUTLS_VERSION_NUMBER >= 0x030201
      ...
     #endif

Building the source
-------------------

If you want to compile a source file including the gnutls/gnutls.h header file, you must make sure that the compiler can find it in the directory hierarchy.  This is accomplished by adding the path to the directory in which the header file is located to the compilers include file search path (via the -I option).

However, the path to the include file is determined at the time the source is configured.  To solve this problem, the library uses the external package pkg-config that knows the path to the include file and other configuration options.  The options that need to be added to the compiler invocation at compile time are output by the --cflags option to pkg-config gnutls.  The following example shows how it can be used at the command line:

     gcc -c foo.c `pkg-config gnutls --cflags`

Adding the output of pkg-config gnutls --cflags to the compilers command line will ensure that the compiler can find the gnutls/gnutls.h header file.

A similar problem occurs when linking the program with the library. Again, the compiler has to find the library files.  For this to work, the path to the library files has to be added to the library search path (via the -L option).  For this, the option --libs to pkg-config gnutls can be used.  For convenience, this option also outputs all other options that are required to link the program with the library (for instance, the -ltasn1 option).  The example shows how to link foo.o with the library to a program foo.

     gcc -o foo foo.o `pkg-config gnutls --libs`

Of course you can also combine both examples to a single command by specifying both options to pkg-config:

     gcc -o foo foo.c `pkg-config gnutls --cflags --libs`

When a program uses the GNU autoconf system, then the following line or similar can be used to detect the presence of GnuTLS.

     PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.3.0])

     AC_SUBST([LIBGNUTLS_CFLAGS])
     AC_SUBST([LIBGNUTLS_LIBS])

Session initialization
======================

In the previous sections we have discussed the global initialization required for GnuTLS as well as the initialization required for each authentication method's credentials (see Authentication). In this section we elaborate on the TLS or DTLS session initiation. Each session is initialized using gnutls_init which among others is used to specify the type of the connection (server or client), and the underlying protocol type, i.e., datagram (UDP) or reliable (TCP).

gnutls_init

gnutls_init_flags_t,The gnutls_init_flags_t enumeration.

After the session initialization details on the allowed ciphersuites and protocol versions should be set using the priority functions such as gnutls_priority_set and gnutls_priority_set_direct. We elaborate on them in Priority Strings. The credentials used for the key exchange method, such as certificates or usernames and passwords should also be associated with the session current session using gnutls_credentials_set.

gnutls_credentials_set

Associating the credentials
===========================

Each authentication method is associated with a key exchange method, and a credentials type. The contents of the credentials is method-dependent, e.g. certificates for certificate authentication and should be initialized and associated with a session (see gnutls_credentials_set).  A mapping of the key exchange methods with the credential types is shown in tab:key-exchange-cred.

Authentication method   Key exchange   Client credentials   Server credentials

Certificate and Raw public-key
KX_RSA,
KX_DHE_RSA,
KX_DHE_DSS,
KX_ECDHE_RSA,
KX_ECDHE_ECDSA
CRD_CERTIFICATE
CRD_CERTIFICATE

Password and certificate
KX_SRP_RSA, KX_SRP_DSS
CRD_SRP
CRD_CERTIFICATE, CRD_SRP

Password
KX_SRP
CRD_SRP
CRD_SRP

Anonymous
KX_ANON_DH,
KX_ANON_ECDH
CRD_ANON
CRD_ANON

Pre-shared key
KX_PSK,
KX_DHE_PSK, KX_ECDHE_PSK
CRD_PSK
CRD_PSK

Table: Key exchange algorithms and the corresponding credential types.

Certificates
------------

Server certificate authentication
.................................

When using certificates the server is required to have at least one certificate and private key pair. Clients may not hold such a pair, but a server could require it. In this section we discuss general issues applying to both client and server certificates. The next section will elaborate on issues arising from client authentication only.

In order to use certificate credentials one must first initialize a credentials structure of type gnutls_certificate_credentials_t. After use this structure must be freed. This can be done with the following functions.

gnutls_certificate_allocate_credentials,gnutls_certificate_free_credentials

After the credentials structures are initialized, the certificate and key pair must be loaded. This occurs before any TLS session is initialized, and the same structures are reused for multiple sessions. Depending on the certificate type different loading functions are available, as shown below. For X.509 certificates, the functions will accept and use a certificate chain that leads to a trusted authority. The certificate chain must be ordered in such way that every certificate certifies the one before it. The trusted authority's certificate need not to be included since the peer should possess it already.

gnutls_certificate_set_x509_key_file2,gnutls_certificate_set_x509_key_mem2,gnutls_certificate_set_x509_key

It is recommended to use the higher level functions such as gnutls_certificate_set_x509_key_file2 which accept not only file names but URLs that specify objects stored in token, or system certificates and keys (see Application-specific keys). For these cases, another important function is gnutls_certificate_set_pin_function, that allows setting a callback function to retrieve a PIN if the input keys are protected by PIN.

gnutls_certificate_set_pin_function

If the imported keys and certificates need to be accessed before any TLS session is established, it is convenient to use gnutls_certificate_set_key in combination with gnutls_pcert_import_x509_raw and gnutls_privkey_import_x509_raw.

gnutls_certificate_set_key

If multiple certificates are used with the functions above each client's request will be served with the certificate that matches the requested name (see Server name indication).

As an alternative to loading from files or buffers, a callback may be used for the server or the client to specify the certificate and the key at the handshake time. In that case a certificate should be selected according the peer's signature algorithm preferences. To get those preferences use gnutls_sign_algorithm_get_requested. Both functions are shown below.

gnutls_certificate_set_retrieve_function,gnutls_certificate_set_retrieve_function2,gnutls_certificate_set_retrieve_function3,gnutls_sign_algorithm_get_requested

The functions above do not handle the requested server name automatically. A server would need to check the name requested by the client using gnutls_server_name_get, and serve the appropriate certificate. Note that some of these functions require the gnutls_pcert_st structure to be filled in. Helper functions to fill in the structure are listed below.

typedef struct gnutls_pcert_st
{
  gnutls_pubkey_t pubkey;
  gnutls_datum_t cert;
  gnutls_certificate_type_t type;
} gnutls_pcert_st;

gnutls_pcert_import_x509,gnutls_pcert_import_x509_raw,gnutls_pcert_deinit

In a handshake, the negotiated cipher suite depends on the certificate's parameters, so some key exchange methods might not be available with all certificates. GnuTLS will disable ciphersuites that are not compatible with the key, or the enabled authentication methods.  For example keys marked as sign-only, will not be able to access the plain RSA ciphersuites, that require decryption. It is not recommended to use RSA keys for both signing and encryption. If possible use a different key for the DHE-RSA which uses signing and RSA that requires decryption. All the key exchange methods shown in tab:key-exchange are available in certificate authentication.

Client certificate authentication
.................................

If a certificate is to be requested from the client during the handshake, the server will send a certificate request message. This behavior is controlled by gnutls_certificate_server_set_request. The request contains a list of the by the server accepted certificate signers. This list is constructed using the trusted certificate authorities of the server. 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_server_set_request

gnutls_certificate_send_x509_rdn_sequence

On the client side, it needs to set its certificates on the credentials structure, similarly to server side from a file, or via a callback. Once the certificates are available in the credentials structure, the client will send them if during the handshake the server requests a certificate signed by the issuer of its CA.

In the case a single certificate is available and the server does not specify a signer's list, then that certificate is always sent. It is, however possible, to send a certificate even when the advertised CA list by the server contains CAs other than its signer. That can be achieved using the GNUTLS_FORCE_CLIENT_CERT flag in gnutls_init.

gnutls_certificate_set_x509_key_file,gnutls_certificate_set_x509_simple_pkcs12_file,gnutls_certificate_set_retrieve_function2

Client or server certificate verification
.........................................

Certificate verification is possible by loading the trusted authorities into the credentials structure by using the following functions, applicable to X.509 certificates. In modern systems it is recommended to utilize gnutls_certificate_set_x509_system_trust which will load the trusted authorities from the system store.

gnutls_certificate_set_x509_system_trust gnutls_certificate_set_x509_trust_file,gnutls_certificate_set_x509_trust_dir

The peer's certificate will be automatically verified if gnutls_session_set_verify_cert is called prior to handshake.

Alternatively, one must set a callback function during the handshake using gnutls_certificate_set_verify_function, which will verify the peer's certificate once received. The verification should happen using gnutls_certificate_verify_peers3 within the callback. It will verify the certificate's signature and the owner of the certificate. That will provide a brief verification output. If a detailed output is required one should call gnutls_certificate_get_peers to obtain the raw certificate of the peer and verify it using the functions discussed in X.509 certificates.

In both the automatic and the manual cases, the verification status returned can be printed using gnutls_certificate_verification_status_print.

gnutls_session_set_verify_cert

gnutls_certificate_verify_peers3,gnutls_certificate_set_verify_function

Note that when using raw public-keys verification will not work because there is no corresponding certificate body belonging to the raw key that can be verified. In that case the gnutls_certificate_verify_peers family of functions will return a GNUTLS_E_INVALID_REQUEST error code. For authenticating raw public-keys one must use an out-of-band mechanism, e.g. by comparing hashes or using trust on first use (see Verifying a certificate using trust on first use authentication).

Raw public-keys
---------------

As of version 3.6.6 GnuTLS supports Raw public-keys. With raw public-keys only the public-key part (that is normally embedded in a certificate) is transmitted to the peer. In order to load a raw public-key and its corresponding private key in a credentials structure one can use the following functions.

gnutls_certificate_set_key,gnutls_certificate_set_rawpk_key_mem,gnutls_certificate_set_rawpk_key_file

SRP
---

The initialization functions in SRP credentials differ between client and server. Clients supporting SRP should set the username and password prior to connection, to the credentials structure. Alternatively gnutls_srp_set_client_credentials_function may be used instead, to specify a callback function that should return the SRP username and password. The callback is called once during the TLS handshake.

gnutls_srp_allocate_server_credentials,gnutls_srp_allocate_client_credentials,gnutls_srp_free_server_credentials,gnutls_srp_free_client_credentials,gnutls_srp_set_client_credentials

gnutls_srp_set_client_credentials_function

In server side the default behavior of GnuTLS is to read the usernames and SRP verifiers from password files. These password file format is compatible the with the Stanford srp libraries format.  If a different password file format is to be used, then gnutls_srp_set_server_credentials_function should be called, to set an appropriate callback.

gnutls_srp_set_server_credentials_file

gnutls_srp_set_server_credentials_function

PSK
---

The initialization functions in PSK credentials differ between client and server.

gnutls_psk_allocate_server_credentials,gnutls_psk_allocate_client_credentials,gnutls_psk_free_server_credentials,gnutls_psk_free_client_credentials

Clients supporting PSK should supply the username and key before a TLS session is established.  Alternatively gnutls_psk_set_client_credentials_function can be used to specify a callback function. This has the advantage that the callback will be called only if PSK has been negotiated.

gnutls_psk_set_client_credentials

gnutls_psk_set_client_credentials_function

In server side the default behavior of GnuTLS is to read the usernames and PSK keys from a password file. The password file should contain usernames and keys in hexadecimal format. The name of the password file can be stored to the credentials structure by calling gnutls_psk_set_server_credentials_file.  If a different password file format is to be used, then a callback should be set instead by gnutls_psk_set_server_credentials_function.

The server can help the client chose a suitable username and password, by sending a hint. Note that there is no common profile for the PSK hint and applications are discouraged to use it. A server, may specify the hint by calling gnutls_psk_set_server_credentials_hint.  The client can retrieve the hint, for example in the callback function, using gnutls_psk_client_get_hint.

gnutls_psk_set_server_credentials_file

gnutls_psk_set_server_credentials_function,gnutls_psk_set_server_credentials_hint,gnutls_psk_client_get_hint

Anonymous
---------

The key exchange methods for anonymous authentication since GnuTLS 3.6.0 will utilize the RFC7919 parameters, unless explicit parameters have been provided and associated with an anonymous credentials structure. Check Parameter generation for more information. The initialization functions for the credentials are shown below.

gnutls_anon_allocate_server_credentials,gnutls_anon_allocate_client_credentials,gnutls_anon_free_server_credentials,gnutls_anon_free_client_credentials

Setting up the transport layer
==============================

The next step is to setup the underlying transport layer details. The Berkeley sockets are implicitly used by GnuTLS, thus a call to gnutls_transport_set_int would be sufficient to specify the socket descriptor.

gnutls_transport_set_int,gnutls_transport_set_int2

If however another transport layer than TCP is selected, then a pointer should be used instead to express the parameter to be passed to custom functions. In that case the following functions should be used instead.

gnutls_transport_set_ptr,gnutls_transport_set_ptr2

Moreover all of the following push and pull callbacks should be set.

gnutls_transport_set_push_function gnutls_transport_set_vec_push_function gnutls_transport_set_pull_function gnutls_transport_set_pull_timeout_function

The functions above accept a callback function which should return the number of bytes written, or -1 on error and should set errno appropriately. In some environments, setting errno is unreliable. For example Windows have several errno variables in different CRTs, or in other systems it may be a non thread-local variable.  If this is a concern to you, call gnutls_transport_set_errno with the intended errno value instead of setting errno directly.

gnutls_transport_set_errno

GnuTLS currently only interprets the EINTR, EAGAIN and EMSGSIZE errno values and returns the corresponding GnuTLS error codes:

  * GNUTLS_E_INTERRUPTED

  * GNUTLS_E_AGAIN

  * GNUTLS_E_LARGE_PACKET

The EINTR and EAGAIN values are returned by interrupted system calls, or when non blocking IO is used.  All GnuTLS functions can be resumed (called again), if any of the above error codes is returned. The EMSGSIZE value is returned when attempting to send a large datagram.

In the case of DTLS it is also desirable to override the generic transport functions with functions that emulate the operation of recvfrom and sendto. In addition DTLS requires timers during the receive of a handshake message, set using the gnutls_transport_set_pull_timeout_function function. To check the retransmission timers the function gnutls_dtls_get_timeout is provided, which returns the time remaining until the next retransmission, or better the time until gnutls_handshake should be called again.

gnutls_transport_set_pull_timeout_function gnutls_dtls_get_timeout

Asynchronous operation
----------------------

GnuTLS can be used with asynchronous socket or event-driven programming. The approach is similar to using Berkeley sockets under such an environment. The blocking, due to network interaction, calls such as gnutls_handshake, gnutls_record_recv, can be set to non-blocking by setting the underlying sockets to non-blocking. If other push and pull functions are setup, then they should behave the same way as recv and send when used in a non-blocking way, i.e., return -1 and set errno to EAGAIN. Since, during a TLS protocol session GnuTLS does not block except for network interaction, the non blocking EAGAIN errno will be propagated and GnuTLS functions will return the GNUTLS_E_AGAIN error code. Such calls can be resumed the same way as a system call would. The only exception is gnutls_record_send, which if interrupted subsequent calls need not to include the data to be sent (can be called with NULL argument).

When using the poll or select system calls though, one should remember that they only apply to the kernel sockets API. To check for any available buffered data in a GnuTLS session, utilize gnutls_record_check_pending, either before the poll system call, or after a call to gnutls_record_recv. Data queued by gnutls_record_send (when interrupted) can be discarded using gnutls_record_discard_queued.

An example of GnuTLS' usage with asynchronous operation can be found in doc/examples/tlsproxy.

The following paragraphs describe the detailed requirements for non-blocking operation when using the TLS or DTLS protocols.

TLS protocol
............

There are no special requirements for the TLS protocol operation in non-blocking mode if a non-blocking socket is used.

It is recommended, however, for future compatibility, when in non-blocking mode, to call the gnutls_init function with the GNUTLS_NONBLOCK flag set (see Session initialization).

Datagram TLS protocol
.....................

When in non-blocking mode the function, the gnutls_init function must be called with the GNUTLS_NONBLOCK flag set (see Session initialization).

In contrast with the TLS protocol, the pull timeout function is required, but will only be called with a timeout of zero. In that case it should indicate whether there are data to be received or not. When not using the default pull function, then gnutls_transport_set_pull_timeout_function should be called.

Although in the TLS protocol implementation each call to receive or send function implies to restoring the same function that was interrupted, in the DTLS protocol this requirement isn't true. There are cases where a retransmission is required, which are indicated by a received message and thus gnutls_record_get_direction must be called to decide which direction to check prior to restoring a function call. gnutls_record_get_direction

When calling gnutls_handshake through a multi-plexer, to be able to handle properly the DTLS handshake retransmission timers, the function gnutls_dtls_get_timeout should be used to estimate when to call gnutls_handshake if no data have been received.

Reducing round-trips
--------------------

The full TLS 1.2 handshake requires 2 round-trips to complete, and when combined with TCP's SYN and SYN-ACK negotiation it extends to 3 full round-trips. While, TLS 1.3 reduces that to two round-trips when under TCP, it still adds considerable latency, making the protocol unsuitable for certain applications.

To optimize the handshake latency, in client side, it is possible to take advantage of the TCP fast open RFC7413 mechanism on operating systems that support it. That can be done either by manually crafting the push and pull callbacks, or by utilizing gnutls_transport_set_fastopen. In that case the initial TCP handshake is eliminated, reducing the TLS 1.2 handshake round-trip to 2, and the TLS 1.3 handshake to a single round-trip. Note, that when this function is used, any connection failures will be reported during the gnutls_handshake function call with error code GNUTLS_E_PUSH_ERROR.

gnutls_transport_set_fastopen

When restricted to TLS 1.2, and non-resumed sessions, it is possible to further reduce the round-trips to a single one by taking advantage of the False Start TLS extension. This can be enabled by setting the GNUTLS_ENABLE_FALSE_START flag on gnutls_init.

Under TLS 1.3, the server side can start transmitting before the handshake is complete (i.e., while the client Finished message is still in flight), when no client certificate authentication is requested. This, unlike false start, is part of protocol design with no known security implications. It can be enabled by setting the GNUTLS_ENABLE_EARLY_START on gnutls_init, and the gnutls_handshake function will return early, allowing the server to send data earlier.

Zero-roundtrip mode
-------------------

Under TLS 1.3, when the client has already connected to the server and is resuming a session, it can start transmitting application data during handshake.  This is called zero round-trip time (0-RTT) mode, and the application data sent in this mode is called early data.  The client can send early data with gnutls_record_send_early_data.  The client should call this function before calling gnutls_handshake and after calling gnutls_session_set_data.

Note, however, that early data has weaker security properties than normal application data sent after handshake, such as lack of forward secrecy, no guarantees of non-replay between connections.  Thus it is disabled on the server side by default.  To enable it, the server needs to:

 1. Set GNUTLS_ENABLE_EARLY_DATA on gnutls_init.  Note that this option only has effect on server.

 2. Enable anti-replay measure.  See Anti-replay protection for the details.

The server caches the received early data until it is read.  To set the maximum amount of data to be stored in the cache, use gnutls_record_set_max_early_data_size.  After receiving the EndOfEarlyData handshake message, the server can start retrieving the received data with gnutls_record_recv_early_data.  You can call the function either after the handshake is complete, or through a handshake hook (gnutls_handshake_set_hook_function).

When sending early data, the client should respect the maximum amount of early data, which may have been previously advertised by the server.  It can be checked using gnutls_record_get_max_early_data_size, right after calling gnutls_session_set_data.

After sending early data, to check whether the sent early data was accepted by the server, use gnutls_session_get_flags and compare the result with GNUTLS_SFLAGS_EARLY_DATA. Similarly, on the server side, the same function and flag can be used to check whether it has actually accepted early data.

Anti-replay protection
----------------------

When 0-RTT mode is used, the server must protect itself from replay attacks, where adversary client reuses duplicate session ticket to send early data, before the server authenticates the client.

GnuTLS provides a simple mechanism against replay attacks, following the method called ClientHello recording.  When a session ticket is accepted, the server checks if the ClientHello message has been already seen.  If there is a duplicate, the server rejects early data.

The problem of this approach is that the number of recorded messages grows indefinitely.  To prevent that, the server can limit the recording to a certain time window, which can be configured with gnutls_anti_replay_set_window.

The anti-replay mechanism shall be globally initialized with gnutls_anti_replay_init, and then attached to a session using gnutls_anti_replay_enable.  It can be deinitialized with gnutls_anti_replay_deinit.

The server must also set up a database back-end to store ClientHello messages.  That can be achieved using gnutls_anti_replay_set_add_function and gnutls_anti_replay_set_ptr.

Note that, if the back-end stores arbitrary number of ClientHello, it needs to periodically clean up the stored entries based on the time window set with gnutls_anti_replay_set_window.  The cleanup can be implemented by iterating through the database entries and calling gnutls_db_check_entry_expire_time.  This is similar to session database cleanup used by TLS1.2 sessions.

The full set up of the server using early data would be like the following example:

     #define MAX_EARLY_DATA_SIZE 16384

     static int
     db_add_func(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
     {
         /* Return GNUTLS_E_DB_ENTRY_EXISTS, if KEY is found in the database.
          * Otherwise, store it and return 0.
          */
     }

     static int
     handshake_hook_func(gnutls_session_t session, unsigned int htype,
                         unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
     {
         int ret;
         char buf[MAX_EARLY_DATA_SIZE];

         assert(htype == GNUTLS_HANDSHAKE_END_OF_EARLY_DATA);
         assert(when == GNUTLS_HOOK_POST);

         if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA) {
             ret = gnutls_record_recv_early_data(session, buf, sizeof(buf));
             assert(ret >= 0);
         }

         return ret;
     }

     int main(void)
     {
       ...
       /* Initialize anti-replay measure, which can be shared
        * among multiple sessions.
        */
       gnutls_anti_replay_init(&anti_replay);

       /* Set the database back-end function for the anti-replay data. */
       gnutls_anti_replay_set_add_function(anti_replay, db_add_func);
       gnutls_anti_replay_set_ptr(anti_replay, NULL);

       ...

       gnutls_init(&server, GNUTLS_SERVER | GNUTLS_ENABLE_EARLY_DATA);
       gnutls_record_set_max_early_data_size(server, MAX_EARLY_DATA_SIZE);

       ...

       /* Set the anti-replay measure to the session.
        */
       gnutls_anti_replay_enable(server, anti_replay);
       ...

       /* Retrieve early data in a handshake hook;
        * you can also do that after handshake.
        */
       gnutls_handshake_set_hook_function(server, GNUTLS_HANDSHAKE_END_OF_EARLY_DATA,
                                          GNUTLS_HOOK_POST, handshake_hook_func);
       ...
     }

DTLS sessions
-------------

Because datagram TLS can operate over connections where the client cannot be reliably verified, functionality in the form of cookies, is available to prevent denial of service attacks to servers. GnuTLS requires a server to generate a secret key that is used to sign a cookie (A key of 128 bits or 16 bytes should be sufficient for this purpose.). That cookie is sent to the client using gnutls_dtls_cookie_send, and the client must reply using the correct cookie. The server side should verify the initial message sent by client using gnutls_dtls_cookie_verify. If successful the session should be initialized and associated with the cookie using gnutls_dtls_prestate_set, before proceeding to the handshake.

gnutls_key_generate,gnutls_dtls_cookie_send,gnutls_dtls_cookie_verify,gnutls_dtls_prestate_set

Note that the above apply to server side only and they are not mandatory to be used. Not using them, however, allows denial of service attacks. The client side cookie handling is part of gnutls_handshake.

Datagrams are typically restricted by a maximum transfer unit (MTU). For that both client and server side should set the correct maximum transfer unit for the layer underneath GnuTLS. This will allow proper fragmentation of DTLS messages and prevent messages from being silently discarded by the transport layer. The ``correct'' maximum transfer unit can be obtained through a path MTU discovery mechanism RFC4821.

gnutls_dtls_set_mtu,gnutls_dtls_get_mtu,gnutls_dtls_get_data_mtu

DTLS and SCTP
-------------

Although DTLS can run under any reliable or unreliable layer, there are special requirements for SCTP according to RFC6083. We summarize the most important below, however for a full treatment we refer to RFC6083.

  * The MTU set via gnutls_dtls_set_mtu must be 2^14.

  * Replay detection must be disabled; use the flag GNUTLS_NO_REPLAY_PROTECTION with gnutls_init.

  * Retransmission of messages must be disabled; use gnutls_dtls_set_timeouts with a retransmission timeout larger than the total.

  * Handshake, Alert and ChangeCipherSpec messages must be sent over stream 0 with unlimited reliability and with the ordered delivery feature.

  * During a rehandshake, the caching of messages with unknown epoch is not handled by GnuTLS; this must be implemented in a special pull function.

TLS handshake
=============

Once a session has been initialized and a network connection has been set up, TLS and DTLS protocols perform a handshake. The handshake is the actual key exchange.

gnutls_handshake

gnutls_handshake_set_timeout

In GnuTLS 3.5.0 and later it is recommended to use gnutls_session_set_verify_cert for the handshake process to ensure the verification of the peer's identity. That will verify the peer's certificate, against the trusted CA store while accounting for stapled OCSP responses during the handshake; any error will be returned as a handshake error.

In older GnuTLS versions it is required to verify the peer's certificate during the handshake by setting a callback with gnutls_certificate_set_verify_function, and then using gnutls_certificate_verify_peers3 from it. See Certificate authentication for more information.

gnutls_session_set_verify_cert,gnutls_certificate_verify_peers3

Data transfer and termination
=============================

Once the handshake is complete and peer's identity has been verified data can be exchanged. The available functions resemble the POSIX recv and send functions. It is suggested to use gnutls_error_is_fatal to check whether the error codes returned by these functions are fatal for the protocol or can be ignored.

gnutls_record_send

gnutls_record_recv

gnutls_error_is_fatal

Although, in the TLS protocol the receive function can be called at any time, when DTLS is used the GnuTLS receive functions must be called once a message is available for reading, even if no data are expected. This is because in DTLS various (internal) actions may be required due to retransmission timers. Moreover, an extended receive function is shown below, which allows the extraction of the message's sequence number. Due to the unreliable nature of the protocol, this field allows distinguishing out-of-order messages.

gnutls_record_recv_seq

The gnutls_record_check_pending helper function is available to allow checking whether data are available to be read in a GnuTLS session buffers. Note that this function complements but does not replace poll, i.e., gnutls_record_check_pending reports no data to be read, poll should be called to check for data in the network buffers.

gnutls_record_check_pending gnutls_record_get_direction

Once a TLS or DTLS session is no longer needed, it is recommended to use gnutls_bye to terminate the session. That way the peer is notified securely about the intention of termination, which allows distinguishing it from a malicious connection termination. A session can be deinitialized with the gnutls_deinit function.

gnutls_bye gnutls_deinit

Buffered data transfer
======================

Although gnutls_record_send is sufficient to transmit data to the peer, when many small chunks of data are to be transmitted it is inefficient and wastes bandwidth due to the TLS record overhead. In that case it is preferable to combine the small chunks before transmission. The following functions provide that functionality.

gnutls_record_cork

gnutls_record_uncork

Handling alerts
===============

During a TLS connection alert messages may be exchanged by the two peers. Those messages may be fatal, meaning the connection must be terminated afterwards, or warning when something needs to be reported to the peer, but without interrupting the session. The error codes GNUTLS_E_WARNING_ALERT_RECEIVED or GNUTLS_E_FATAL_ALERT_RECEIVED signal those alerts when received, and may be returned by all GnuTLS functions that receive data from the peer, being gnutls_handshake and gnutls_record_recv.

If those error codes are received the alert and its level should be logged or reported to the peer using the functions below.

gnutls_alert_get gnutls_alert_get_name

The peer may also be warned or notified of a fatal issue by using one of the functions below. All the available alerts are listed in The Alert Protocol.

gnutls_alert_send gnutls_error_to_alert

Priority strings
================

How to use Priority Strings
---------------------------

The GnuTLS priority strings specify the TLS session's handshake algorithms and options in a compact, easy-to-use format. These strings are intended as a user-specified override of the library defaults.

That is, we recommend applications using the default settings (c.f. gnutls_set_default_priority or gnutls_set_default_priority_append), and provide the user with access to priority strings for overriding the default behavior, on configuration files, or other UI. Following such a principle, makes the GnuTLS library as the default settings provider. That is necessary and a good practice, because TLS protocol hardening and phasing out of legacy algorithms, is easier to coordinate when happens in a single library.

gnutls_set_default_priority,gnutls_set_default_priority_append,gnutls_priority_set_direct

The priority string translation to the internal GnuTLS form requires processing and the generated internal form also occupies some memory. For that, it is recommended to do that processing once in server side, and share the generated data across sessions. The following functions allow the generation of a "priority cache" and the sharing of it across sessions.

gnutls_priority_init2,gnutls_priority_init,gnutls_priority_set,gnutls_priority_deinit

Using Priority Strings
----------------------

A priority string string may contain a single initial keyword such as in tab:prio-keywords and may be followed by additional algorithm or special keywords. Note that their description is intentionally avoiding specific algorithm details, as the priority strings are not constant between gnutls versions (they are periodically updated to account for cryptographic advances while providing compatibility with old clients and servers).

Keyword   Description
@KEYWORD
Means that a compile-time specified system configuration file (see System-wide configuration of the library)
will be used to expand the provided keyword. That is used to impose system-specific policies.
It may be followed by additional options that will be appended to the
system string (e.g., "@SYSTEM:+SRP"). The system file should have the
format 'KEYWORD=VALUE', e.g., 'SYSTEM=NORMAL:+ARCFOUR-128'.

Since version 3.5.1 it is allowed to specify fallback keywords such
as @KEYWORD1,@KEYWORD2, and the first valid keyword will be used.

PERFORMANCE
All the known to be secure ciphersuites are enabled,
limited to 128 bit ciphers and sorted by terms of speed
performance. The message authenticity security level is of 64 bits or more,
and the certificate verification profile is set to GNUTLS_PROFILE_LOW (80-bits).

NORMAL
Means all the known to be secure ciphersuites. The ciphers are sorted by security
margin, although the 256-bit ciphers are included as a fallback only.
The message authenticity security level is of 64 bits or more,
and the certificate verification profile is set to GNUTLS_PROFILE_LOW (80-bits).

This priority string implicitly enables ECDHE and DHE. The ECDHE ciphersuites
are placed first in the priority order, but due to compatibility
issues with the DHE ciphersuites they are placed last in the priority order,
after the plain RSA ciphersuites.

LEGACY
This sets the NORMAL settings that were used for GnuTLS 3.2.x or earlier. There is
no verification profile set, and the allowed DH primes are considered
weak today (but are often used by misconfigured servers).

PFS
Means all the known to be secure ciphersuites that support perfect forward
secrecy (ECDHE and DHE). The ciphers are sorted by security
margin, although the 256-bit ciphers are included as a fallback only.
The message authenticity security level is of 80 bits or more,
and the certificate verification profile is set to GNUTLS_PROFILE_LOW (80-bits).
This option is available since 3.2.4 or later.

SECURE128
Means all known to be secure ciphersuites that offer a
security level 128-bit or more.
The message authenticity security level is of 80 bits or more,
and the certificate verification profile is set to GNUTLS_PROFILE_LOW (80-bits).

SECURE192
Means all the known to be secure ciphersuites that offer a
security level 192-bit or more.
The message authenticity security level is of 128 bits or more,
and the certificate verification profile is set to GNUTLS_PROFILE_HIGH (128-bits).

SECURE256
Currently alias for SECURE192. This option, will enable ciphers which use a
256-bit key but, due to limitations of the TLS protocol, the overall security
level will be 192-bits (the security level depends on more factors than cipher key size).

SUITEB128
Means all the NSA Suite B cryptography (RFC5430) ciphersuites
with an 128 bit security level, as well as the enabling of the corresponding
verification profile.

SUITEB192
Means all the NSA Suite B cryptography (RFC5430) ciphersuites
with an 192 bit security level, as well as the enabling of the corresponding
verification profile.

NONE
Means nothing is enabled.  This disables even protocol versions.
It should be followed by the algorithms to be enabled. Note that
using this option to build a priority string gives detailed control
into the resulting settings, however with new revisions of the TLS protocol
new priority items are routinely added, and such strings are not
forward compatible with new protocols. As such, we
advice against using that option for applications targeting multiple versions
of the GnuTLS library, and recommend using the defaults (see above) or
adjusting the defaults via gnutls_set_default_priority_append.

Table: Supported initial keywords.

Unless the initial keyword is "NONE" the defaults (in preference order) are for TLS protocols TLS 1.2, TLS1.1, TLS1.0; for certificate types X.509. In key exchange algorithms when in NORMAL or SECURE levels the perfect forward secrecy algorithms take precedence of the other protocols.  In all cases all the supported key exchange algorithms are enabled.

Note that the SECURE levels distinguish between overall security level and message authenticity security level. That is because the message authenticity security level requires the adversary to break the algorithms at real-time during the protocol run, whilst the overall security level refers to off-line adversaries (e.g. adversaries breaking the ciphertext years after it was captured).

The NONE keyword, if used, must followed by keywords specifying the algorithms and protocols to be enabled. The other initial keywords do not require, but may be followed by such keywords. All level keywords can be combined, and for example a level of "SECURE256:+SECURE128" is allowed.

The order with which every algorithm or protocol is specified is significant. Algorithms specified before others will take precedence. The supported in the GnuTLS version corresponding to this document algorithms and protocols are shown in tab:prio-algorithms; to list the supported algorithms in your currently using version use gnutls-cli -l.

To avoid collisions in order to specify a protocol version with "VERS-", signature algorithms with "SIGN-" and certificate types with "CTYPE-". All other algorithms don't need a prefix. Each specified keyword (except for special keywords) can be prefixed with any of the following characters.

'!' or '-'
     appended with an algorithm will remove this algorithm.

"+"
     appended with an algorithm will add this algorithm.

Type   Keywords
Ciphers
Examples are AES-128-GCM, AES-256-GCM, AES-256-CBC, GOST28147-TC26Z-CNT; see also
tab:ciphers for more options. Catch all name is CIPHER-ALL which will add
all the algorithms from NORMAL priority. The shortcut for secure GOST
algorithms is CIPHER-GOST-ALL.

Key exchange
RSA, RSA-PSK, RSA-EXPORT, DHE-RSA, DHE-DSS, SRP, SRP-RSA, SRP-DSS,
PSK, DHE-PSK, ECDHE-PSK, ECDHE-RSA, ECDHE-ECDSA, VKO-GOST-12, ANON-ECDH, ANON-DH.
Catch all name is KX-ALL which will add all the algorithms from NORMAL
priority. Under TLS1.3, the DHE-PSK and ECDHE-PSK strings are equivalent
and instruct for a Diffie-Hellman key exchange using the enabled groups. The
shortcut for secure GOST algorithms is KX-GOST-ALL.

MAC
MD5, SHA1, SHA256, SHA384, GOST28147-TC26Z-IMIT, AEAD (used with
GCM ciphers only). All algorithms from NORMAL priority can be accessed with
MAC-ALL. The shortcut for secure GOST algorithms is MAC-GOST-ALL.

Compression algorithms
COMP-NULL, COMP-DEFLATE. Catch all is COMP-ALL.

TLS versions
VERS-TLS1.0, VERS-TLS1.1, VERS-TLS1.2, VERS-TLS1.3,
VERS-DTLS0.9, VERS-DTLS1.0, VERS-DTLS1.2.
Catch all are VERS-ALL, and will enable
all protocols from NORMAL priority. To distinguish between TLS and DTLS
versions you can use VERS-TLS-ALL and VERS-DTLS-ALL.

Signature algorithms
SIGN-RSA-SHA1, SIGN-RSA-SHA224,
SIGN-RSA-SHA256, SIGN-RSA-SHA384, SIGN-RSA-SHA512, SIGN-DSA-SHA1,
SIGN-DSA-SHA224, SIGN-DSA-SHA256, SIGN-RSA-MD5, SIGN-ECDSA-SHA1,
SIGN-ECDSA-SHA224, SIGN-ECDSA-SHA256, SIGN-ECDSA-SHA384, SIGN-ECDSA-SHA512,
SIGN-EdDSA-Ed25519, SIGN-EdDSA-Ed448,
SIGN-RSA-PSS-SHA256, SIGN-RSA-PSS-SHA384, SIGN-RSA-PSS-SHA512,
SIGN-GOSTR341001, SIGN-GOSTR341012-256, SIGN-GOSTR341012-512.
Catch all which enables all algorithms from NORMAL priority is SIGN-ALL.
Shortcut which enables secure GOST algorithms is SIGN-GOST-ALL.
This option is only considered for TLS 1.2 and later.

Groups
GROUP-SECP192R1, GROUP-SECP224R1, GROUP-SECP256R1, GROUP-SECP384R1,
GROUP-SECP521R1, GROUP-X25519, GROUP-X448, GROUP-GC256B, GROUP-GC512A,
GROUP-FFDHE2048, GROUP-FFDHE3072, GROUP-FFDHE4096, GROUP-FFDHE6144, and
GROUP-FFDHE8192.
Groups include both elliptic curve groups, e.g., SECP256R1, as well as
finite field groups such as FFDHE2048. Catch all which enables all groups
from NORMAL priority is GROUP-ALL. The helper keywords GROUP-DH-ALL,
GROUP-GOST-ALL and GROUP-EC-ALL are also available, restricting the groups
to finite fields (DH), GOST curves and generic elliptic curves.

Elliptic curves (legacy)
CURVE-SECP192R1, CURVE-SECP224R1, CURVE-SECP256R1, CURVE-SECP384R1,
CURVE-SECP521R1, CURVE-X25519, and CURVE-X448.
Catch all which enables all curves from NORMAL priority is CURVE-ALL. Note
that the CURVE keyword is kept for backwards compatibility only, for new
applications see the GROUP keyword above.

Certificate types
Certificate types can be given in a symmetric fashion (i.e. the same for
both client and server) or, as of GnuTLS 3.6.4, in an asymmetric fashion
(i.e. different for the client than for the server). Alternative certificate
types must be explicitly enabled via flags in gnutls_init.

The currently supported types are CTYPE-X509, CTYPE-RAWPK which apply both to
client and server; catch all is CTYPE-ALL. The types CTYPE-CLI-X509, CTYPE-SRV-X509,
CTYPE-CLI-RAWPK, CTYPE-SRV-RAWPK can be used to specialize on client or server;
catch all is CTYPE-CLI-ALL and CTYPE-SRV-ALL. The type 'X509' is aliased to 'X.509'
for legacy reasons.

Generic
The keyword GOST is a shortcut for secure GOST algorithms (MACs, ciphers,
KXes, groups and signatures). For example the following string will enable all
TLS 1.2 GOST ciphersuites: 'NONE:+VERS-TLS1.2:+GOST'.

Table: The supported algorithm keywords in priority strings.

Note that the finite field groups (indicated by the FFDHE prefix) and DHE key exchange methods are generally slower (It depends on the group in use.  Groups with less bits are always faster, but the number of bits ties with the security parameter.  See Selecting cryptographic key sizes for the acceptable security levels.) than their elliptic curves counterpart (ECDHE).

The available special keywords are shown in tab:prio-special1 and tab:prio-special2.

Keyword   Description

%COMPAT
will enable compatibility mode. It might mean that violations
of the protocols are allowed as long as maximum compatibility with
problematic clients and servers is achieved. More specifically this
string will tolerate packets over the maximum allowed TLS record,
and add a padding to TLS Client Hello packet to prevent it being in the
256-512 range which is known to be causing issues with a commonly used
firewall (see the %DUMBFW option).

%DUMBFW
will add a private extension with bogus data that make the client
hello exceed 512 bytes. This avoids a black hole behavior in some
firewalls. This is the RFC7685 client hello padding extension, also enabled
with %COMPAT.

%NO_EXTENSIONS
will prevent the sending of any TLS extensions in client side. Note
that TLS 1.2 requires extensions to be used, as well as safe
renegotiation thus this option must be used with care. When this option
is set no versions later than TLS1.2 can be negotiated.

%NO_SHUFFLE_EXTENSIONS
will prevent randomizing the order of ClientHello extensions. By
default, those extensions are randomized to make fingerprinting harder.

%NO_STATUS_REQUEST
will prevent sending of the TLS status_request extension in client side.

%NO_TICKETS
will prevent the advertizing of the TLS session ticket extension.

%NO_TICKETS_TLS12
will prevent the advertizing of the TLS session ticket extension in TLS 1.2.
This is implied by the PFS keyword.

%NO_SESSION_HASH
will prevent the advertizing the TLS extended master secret (session hash)
extension.

%FORCE_SESSION_HASH
negotiate the TLS extended master secret (session hash) extension.
Specifying both %NO_SESSION_HASH and %FORCE_SESSION_HASH is not
supported, and the behavior is undefined.

%SERVER_PRECEDENCE
The ciphersuite will be selected according to server priorities
and not the client's.

%SSL3_RECORD_VERSION
will use SSL3.0 record version in client hello.
By default GnuTLS will set the minimum supported version as the
client hello record version (do not confuse that version with the
proposed handshake version at the client hello).

%LATEST_RECORD_VERSION
will use the latest TLS version record version in client hello.

Table: Special priority string keywords.

Keyword   Description

%STATELESS_COMPRESSION
ignored; no longer used.

%DISABLE_WILDCARDS
will disable matching wildcards when comparing hostnames
in certificates.

%NO_ETM
will disable the encrypt-then-mac TLS extension (RFC7366). This is
implied by the %COMPAT keyword.

%FORCE_ETM
negotiate CBC ciphersuites only when both sides of the connection support
encrypt-then-mac TLS extension (RFC7366).

%DISABLE_SAFE_RENEGOTIATION
will completely disable safe renegotiation.  Do not use unless you
know what you are doing.

%UNSAFE_RENEGOTIATION
will allow handshakes and re-handshakes
without the safe renegotiation extension.  Note that for clients
this mode is insecure (you may be under attack), and for servers it
will allow insecure clients to connect (which could be fooled by an
attacker).  Do not use unless you know what you are doing and want
maximum compatibility.

%PARTIAL_RENEGOTIATION
will allow initial handshakes to proceed,
but not re-handshakes.  This leaves the client vulnerable to attack,
and servers will be compatible with non-upgraded clients for
initial handshakes.  This is currently the default for clients and
servers, for compatibility reasons.

%SAFE_RENEGOTIATION
will enforce safe renegotiation.  Clients and
servers will refuse to talk to an insecure peer.  Currently this
causes interoperability problems, but is required for full protection.

%FALLBACK_SCSV
will enable the use of the fallback signaling cipher suite value in the
client hello.  Note that this should be set only by applications that
try to reconnect with a downgraded protocol version. See RFC7507 for
details.

%DISABLE_TLS13_COMPAT_MODE
will disable TLS 1.3 middlebox compatibility mode (RFC8446, Appendix
D.4) for non-compliant middleboxes.

%VERIFY_ALLOW_BROKEN
will allow signatures with known to be broken algorithms (such as MD5 or
SHA1) in certificate chains.

%VERIFY_ALLOW_SIGN_RSA_MD5
will allow RSA-MD5 signatures in certificate chains.

%VERIFY_ALLOW_SIGN_WITH_SHA1
will allow signatures with SHA1 hash algorithm in certificate chains.

%VERIFY_DISABLE_CRL_CHECKS
will disable CRL or OCSP checks in the verification of the certificate chain.

%VERIFY_ALLOW_X509_V1_CA_CRT
will allow V1 CAs in chains.

%PROFILE_(LOW|LEGACY|MEDIUM|HIGH|ULTRA|FUTURE)
require a certificate verification profile the corresponds to the specified
security level, see tab:key-sizes for the mappings to values.

%PROFILE_(SUITEB128|SUITEB192)
require a certificate verification profile the corresponds to SUITEB. Note
that an initial keyword that enables SUITEB automatically sets the profile.

Table: More priority string keywords.

Finally the ciphersuites enabled by any priority string can be listed using the gnutls-cli application (see gnutls-cli Invocation), or by using the priority functions as in Listing the ciphersuites in a priority string.

Example priority strings are:

     The system imposed security level:
         "SYSTEM"

     The default priority without the HMAC-MD5:
         "NORMAL:-MD5"

     Specifying RSA with AES-128-CBC:
         "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"

     Specifying the defaults plus ARCFOUR-128:
         "NORMAL:+ARCFOUR-128"

     Enabling the 128-bit secure ciphers, while disabling TLS 1.0:
         "SECURE128:-VERS-TLS1.0"

     Enabling the 128-bit and 192-bit secure ciphers, while disabling all TLS versions
     except TLS 1.2:
         "SECURE128:+SECURE192:-VERS-ALL:+VERS-TLS1.2"

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 (profile)   Description

<64
<768
<128
INSECURE
Considered to be insecure

64
768
128
VERY WEAK
Short term protection against individuals

72
1008
160
WEAK
Short term protection against small organizations

80
1024
160
LOW
Very short term protection against agencies (corresponds to ENISA legacy level)

96
1776
192
LEGACY
Legacy standard level

112
2048
224
MEDIUM
Medium-term protection

128
3072
256
HIGH
Long term protection (corresponds to ENISA future level)

192
8192
384
ULTRA
Even longer term protection

256
15424
512
FUTURE
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.

gnutls_sec_param_get_name

The following functions will set the minimum acceptable group size for Diffie-Hellman and SRP authentication. gnutls_dh_set_prime_bits,gnutls_srp_set_prime_bits

Advanced topics
===============

Virtual hosts and credentials
-----------------------------

Often when operating with virtual hosts, one may not want to associate a particular certificate set to the credentials function early, before the virtual host is known. That can be achieved by calling gnutls_credentials_set within a handshake pre-hook for client hello. That message contains the peer's intended hostname, and if read, and the appropriate credentials are set, gnutls will be able to continue in the handshake process. A brief usage example is shown below.

     static int ext_hook_func(void *ctx, unsigned tls_id,
                              const unsigned char *data, unsigned size)
     {
     	if (tls_id == 0) { /* server name */
     		/* figure the advertised name - the following hack
                      * relies on the fact that this extension only supports
                      * DNS names, and due to a protocol bug cannot be extended
                      * to support anything else. */
     		if (name < 5) return 0;
     		name = data+5;
     		name_size = size-5;
     	}
     	return 0;
     }

     static int
     handshake_hook_func(gnutls_session_t session, unsigned int htype,
                         unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
     {
         int ret;

         assert(htype == GNUTLS_HANDSHAKE_CLIENT_HELLO);
         assert(when == GNUTLS_HOOK_PRE);

         ret = gnutls_ext_raw_parse(NULL, ext_hook_func, msg,
                                    GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
         assert(ret >= 0);

         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);

         return ret;
     }

     int main(void)
     {
       ...

       gnutls_handshake_set_hook_function(server, GNUTLS_HANDSHAKE_CLIENT_HELLO,
                                          GNUTLS_HOOK_PRE, handshake_hook_func);
       ...
     }

gnutls_handshake_set_hook_function

Session resumption
------------------

To reduce time and network traffic spent in a handshake the client can request session resumption from a server that previously shared a session with the client.

Under TLS 1.2, in order to support resumption a server can either store the session security parameters in a local database or use session tickets (see Session tickets) to delegate storage to the client.

Under TLS 1.3, session resumption is only available through session tickets, and multiple tickets could be sent from server to client. That provides the following advantages:

  * When tickets are not re-used the subsequent client sessions cannot be associated with each other by an eavesdropper

  * On post-handshake authentication the server may send different tickets asynchronously for each identity used by client.

Client side
...........

The client has to retrieve and store the session parameters. Before establishing a new session to the same server the parameters must be re-associated with the GnuTLS session using gnutls_session_set_data.

gnutls_session_get_data2,gnutls_session_set_data

Keep in mind that sessions will be expired after some time, depending on the server, and a server may choose not to resume a session even when requested to.  The expiration 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.

gnutls_session_is_resumed

gnutls_session_get_id2

Server side
...........

A server enabling both session tickets and a storage for session data would use session tickets when clients support it and the storage otherwise.

A storing server needs to specify callback functions to store, retrieve and delete session data. These can be registered with the functions below. The stored sessions in the database can be checked using gnutls_db_check_entry for expiration.

gnutls_db_set_retrieve_function,gnutls_db_set_store_function,gnutls_db_set_ptr,gnutls_db_set_remove_function gnutls_db_check_entry

A server supporting session tickets must generate ticket encryption and authentication keys using gnutls_session_ticket_key_generate. Those keys should be associated with the GnuTLS session using gnutls_session_ticket_enable_server.

Those will be the initial keys, but GnuTLS will rotate them regularly. The key rotation interval can be changed with gnutls_db_set_cache_expiration and will be set to three times the ticket expiration time (ie. three times the value given in that function). Every such interval, new keys will be generated from those initial keys. This is a necessary mechanism to prevent the keys from becoming long-term keys and as such preserve forward-secrecy in the issued session tickets. If no explicit key rotation interval is provided, GnuTLS will rotate them every 18 hours by default.

The master key can be shared between processes or between systems. Processes which share the same master key will generate the same rotated subkeys, assuming they share the same time (irrespective of timezone differences).

gnutls_session_ticket_enable_server gnutls_session_ticket_key_generate gnutls_session_resumption_requested

The expiration time for session resumption, either in tickets or stored data is set using gnutls_db_set_cache_expiration. This function also controls the ticket key rotation period. Currently, the session key rotation interval is set to 3 times the expiration time set by this function.

Under TLS 1.3, the server sends by default 2 tickets, and can send additional session tickets at any time using gnutls_session_ticket_send.

gnutls_session_ticket_send

Certificate verification
------------------------

In this section the functionality for additional certificate verification methods is listed. These methods are intended to be used in addition to normal PKI verification, in order to reduce the risk of a compromised CA being undetected.

Trust on first use
..................

The GnuTLS library includes functionality to use an SSH-like trust on first use authentication. The available functions to store and verify public keys are listed below.

gnutls_verify_stored_pubkey gnutls_store_pubkey

In addition to the above the gnutls_store_commitment can be used to implement a key-pinning architecture as in KEYPIN. This provides a way for web server to commit on a public key that is not yet active.

gnutls_store_commitment

The storage and verification functions may be used with the default text file based back-end, or another back-end may be specified. That should contain storage and retrieval functions and specified as below.

gnutls_tdb_init,gnutls_tdb_deinit,gnutls_tdb_set_verify_func,gnutls_tdb_set_store_func,gnutls_tdb_set_store_commitment_func

DANE verification
.................

Since the DANE library is not included in GnuTLS it requires programs to be linked against it. This can be achieved with the following commands.

     gcc -o foo foo.c `pkg-config gnutls-dane --cflags --libs`

When a program uses the GNU autoconf system, then the following line or similar can be used to detect the presence of the library.

     PKG_CHECK_MODULES([LIBDANE], [gnutls-dane >= 3.0.0])

     AC_SUBST([LIBDANE_CFLAGS])
     AC_SUBST([LIBDANE_LIBS])

The high level functionality provided by the DANE library is shown below.

dane_verify_crt

dane_verify_session_crt,dane_strerror

Note that the dane_state_t structure that is accepted by both verification functions is optional. It is required when many queries are performed to optimize against multiple re-initializations of the resolving back-end and loading of DNSSEC keys.

The following flags are returned by the verify functions to indicate the status of the verification.

dane_verify_status_t,The DANE verification status flags.

In order to generate a DANE TLSA entry to use in a DNS server you may use danetool (see danetool Invocation).

TLS 1.2 re-authentication
-------------------------

In TLS 1.2 or earlier there is no distinction between re-key, re-authentication, and re-negotiation. All of these use cases are handled by the TLS' rehandshake process. For that reason in GnuTLS rehandshake is not transparent to the application, and the application must explicitly take control of that process. In addition GnuTLS since version 3.5.0 will not allow the peer to switch identities during a rehandshake. The threat addressed by that behavior depends on the application protocol, but primarily it protects applications from being misled by a rehandshake which switches the peer's identity. Applications can disable this protection by using the GNUTLS_ALLOW_ID_CHANGE flag in gnutls_init.

The following paragraphs explain how to safely use the rehandshake process.

Client side
...........

According to the TLS specification a client may initiate a rehandshake at any time. That can be achieved by calling gnutls_handshake and rely on its return value for the outcome of the handshake (the server may deny a rehandshake). If a server requests a re-handshake, then a call to gnutls_record_recv will return GNUTLS_E_REHANDSHAKE in the client, instructing it to call gnutls_handshake. To deny a rehandshake request by the server it is recommended to send a warning alert of type GNUTLS_A_NO_RENEGOTIATION.

Due to limitations of early protocol versions, it is required to check whether safe renegotiation is in place, i.e., using gnutls_safe_renegotiation_status, which ensures that the server remains the same as the initial.

To make re-authentication transparent to the application when requested by the server, use the GNUTLS_AUTO_REAUTH flag on the gnutls_init call. In that case the re-authentication will happen in the call of gnutls_record_recv that received the reauthentication request.

gnutls_safe_renegotiation_status

Server side
...........

A server which wants to instruct the client to re-authenticate, should call gnutls_rehandshake and wait for the client to re-authenticate. It is recommended to only request re-handshake when safe renegotiation is enabled for that session (see gnutls_safe_renegotiation_status and the discussion in Safe renegotiation). A server could also encounter the GNUTLS_E_REHANDSHAKE error code while receiving data. That indicates a client-initiated re-handshake request. In that case the server could ignore that request, perform handshake (unsafe when done generally), or even drop the connection.

gnutls_rehandshake

TLS 1.3 re-authentication and re-key
------------------------------------

The TLS 1.3 protocol distinguishes between re-key and re-authentication. The re-key process ensures that fresh keys are supplied to the already negotiated parameters, and on GnuTLS can be initiated using gnutls_session_key_update. The re-key process can be one-way (i.e., the calling party only changes its keys), or two-way where the peer is requested to change keys as well.

The re-authentication process, allows the connected client to switch identity by presenting a new certificate. Unlike TLS 1.2, the server is not allowed to change identities. That client re-authentication, or post-handshake authentication can be initiated only by the server using gnutls_reauth, and only if a client has advertised support for it. Both server and client have to explicitly enable support for post handshake authentication using the GNUTLS_POST_HANDSHAKE_AUTH flag at gnutls_init.

A client receiving a re-authentication request will "see" the error code GNUTLS_E_REAUTH_REQUEST at gnutls_record_recv. At this point, it should also call gnutls_reauth.

To make re-authentication transparent to the application when requested by the server, use the GNUTLS_AUTO_REAUTH and GNUTLS_POST_HANDSHAKE_AUTH flags on the gnutls_init call. In that case the re-authentication will happen in the call of gnutls_record_recv that received the reauthentication request.

Parameter generation
--------------------

Prior to GnuTLS 3.6.0 for the ephemeral or anonymous Diffie-Hellman (DH) TLS ciphersuites the application was required to generate or provide DH parameters. That is no longer necessary as GnuTLS utilizes DH parameters and negotiation from RFC7919.

Applications can tune the used parameters by explicitly specifying them in the priority string. In server side applications can set the minimum acceptable level of DH parameters by calling gnutls_certificate_set_known_dh_params, gnutls_anon_set_server_known_dh_params, or gnutls_psk_set_server_known_dh_params, depending on the type of the credentials, to set the lower acceptable parameter limits. Typical applications should rely on the default settings.

gnutls_certificate_set_known_dh_params,gnutls_anon_set_server_known_dh_params,gnutls_psk_set_server_known_dh_params

Legacy parameter generation
...........................

Note that older than 3.5.6 versions of GnuTLS provided functions to generate or import arbitrary DH parameters from a file. This practice is still supported but discouraged in current versions. There is no known advantage from using random parameters, while there have been several occasions where applications were utilizing incorrect, weak or insecure parameters. This is the main reason GnuTLS includes the well-known parameters of RFC7919 and recommends applications utilizing them.

In older applications which require to specify explicit DH parameters, we recommend using certtool (of GnuTLS 3.5.6 or later) with the --get-dh-params option to obtain the FFDHE parameters discussed above. The output parameters of the tool are in PKCS#3 format and can be imported by most existing applications.

The following functions are still supported but considered obsolete.

gnutls_dh_params_generate2,gnutls_dh_params_import_pkcs3,gnutls_certificate_set_dh_params

Deriving keys for other applications/protocols
----------------------------------------------

In several cases, after a TLS connection is established, it is desirable to derive keys to be used in another application or protocol (e.g., in an other TLS session using pre-shared keys). The following describe GnuTLS' implementation of RFC5705 to extract keys based on a session's master secret.

The API to use is gnutls_prf_rfc5705.  The function needs to be provided with a label, and additional context data to mix in the context parameter.

gnutls_prf_rfc5705

For example, after establishing a TLS session using gnutls_handshake, you can obtain 32-bytes to be used as key, using this call:

     #define MYLABEL "EXPORTER-My-protocol-name"
     #define MYCONTEXT "my-protocol's-1st-session"

     char out[32];
     rc = gnutls_prf_rfc5705 (session, sizeof(MYLABEL)-1, MYLABEL,
                              sizeof(MYCONTEXT)-1, MYCONTEXT, 32, out);

The output key depends on TLS' master secret, and is the same on both client and server.

For legacy applications which need to use a more flexible API, there is gnutls_prf, which in addition, allows to switch the mix of the client and server random nonces, using the server_random_first parameter. For additional flexibility and low-level access to the TLS1.2 PRF, there is a low-level TLS PRF interface called gnutls_prf_raw. That however is not functional under newer protocol versions.

Channel bindings
----------------

In user authentication protocols (e.g., EAP or SASL mechanisms) it is useful to have a unique string that identifies the secure channel that is used, to bind together the user authentication with the secure channel.  This can protect against man-in-the-middle attacks in some situations.  That unique string is called a ``channel binding''.  For background and discussion see RFC5056.

In GnuTLS you can extract a channel binding using the gnutls_session_channel_binding function.  Currently only the following types are supported:

  * GNUTLS_CB_TLS_UNIQUE: corresponds to the tls-unique channel binding for TLS defined in RFC5929

  * GNUTLS_CB_TLS_EXPORTER: corresponds to the tls-exporter channel binding for TLS defined in RFC9266

The following example describes how to print the channel binding data. Note that it must be run after a successful TLS handshake.

     {
       gnutls_datum_t cb;
       int rc;

       rc = gnutls_session_channel_binding (session,
                                            GNUTLS_CB_TLS_UNIQUE,
                                            &cb);
       if (rc)
         fprintf (stderr, "Channel binding error: %s\n",
                  gnutls_strerror (rc));
       else
         {
           size_t i;
           printf ("- Channel binding 'tls-unique': ");
           for (i = 0; i < cb.size; i++)
             printf ("%02x", cb.data[i]);
           printf ("\n");
         }
     }

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

The TLS protocols support many ciphersuites, extensions and version numbers. As a result, 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). A conservative priority string that would disable certain TLS protocol options that are known to cause compatibility problems, is shown below.
NORMAL:%COMPAT

For very old broken peers that do not tolerate TLS version numbers over TLS 1.0 another priority string is:
NORMAL:-VERS-ALL:+VERS-TLS1.0:+VERS-SSL3.0:%COMPAT
This priority string will in addition to above, only enable SSL 3.0 and TLS 1.0 as protocols.

Compatibility with the OpenSSL library
--------------------------------------

To ease GnuTLS' integration with existing applications, a compatibility layer with the OpenSSL library is included in the gnutls-openssl library. This compatibility layer is not complete and it is not intended to completely re-implement the OpenSSL API with GnuTLS.  It only provides limited source-level compatibility.

The prototypes for the compatibility functions are in the gnutls/openssl.h header file. The limitations imposed by the compatibility layer include:

  * Error handling is not thread safe.