Blame doc/cha-internals.texi

Packit 549fdc
@node Internal architecture of GnuTLS
Packit 549fdc
@chapter Internal Architecture of GnuTLS
Packit 549fdc
@cindex internal architecture
Packit 549fdc
Packit 549fdc
This chapter is to give a brief description of the
Packit 549fdc
way @acronym{GnuTLS} works. The focus is to give an idea
Packit 549fdc
to potential developers and those who want to know what
Packit 549fdc
happens inside the black box.
Packit 549fdc
Packit 549fdc
@menu
Packit 549fdc
* The TLS Protocol::
Packit 549fdc
* TLS Handshake Protocol::
Packit 549fdc
* TLS Authentication Methods::
Packit 549fdc
* TLS Extension Handling::
Packit 549fdc
* Cryptographic Backend::
Packit 549fdc
* Random Number Generators-internals::
Packit 549fdc
* FIPS140-2 mode::
Packit 549fdc
@end menu
Packit 549fdc
Packit 549fdc
@node The TLS Protocol
Packit 549fdc
@section The TLS Protocol
Packit 549fdc
The main use case for the TLS protocol is shown in @ref{fig-client-server}.
Packit 549fdc
A user of a library implementing the protocol expects no less than this functionality,
Packit 549fdc
i.e., to be able to set parameters such as the accepted security level, perform a
Packit 549fdc
negotiation with the peer and be able to exchange data.
Packit 549fdc
Packit 549fdc
@float Figure,fig-client-server
Packit 549fdc
@image{gnutls-client-server-use-case,9cm}
Packit 549fdc
@caption{TLS protocol use case.}
Packit 549fdc
@end float
Packit 549fdc
Packit 549fdc
@node TLS Handshake Protocol
Packit 549fdc
@section TLS Handshake Protocol
Packit 549fdc
The @acronym{GnuTLS} handshake protocol is implemented as a state
Packit 549fdc
machine that waits for input or returns immediately when the non-blocking
Packit 549fdc
transport layer functions are used. The main idea is shown in @ref{fig-gnutls-handshake}.
Packit 549fdc
Packit 549fdc
@float Figure,fig-gnutls-handshake
Packit 549fdc
@image{gnutls-handshake-state,9cm}
Packit 549fdc
@caption{GnuTLS handshake state machine.}
Packit 549fdc
@end float
Packit 549fdc
Packit 549fdc
Also the way the input is processed varies per ciphersuite. Several 
Packit 549fdc
implementations of the internal handlers are available and 
Packit 549fdc
@funcref{gnutls_handshake} only multiplexes the input to the appropriate 
Packit 549fdc
handler. For example a @acronym{PSK} ciphersuite has a different 
Packit 549fdc
implementation of the @code{process_client_key_exchange} than a
Packit 549fdc
certificate ciphersuite. We illustrate the idea in @ref{fig-gnutls-handshake-sequence}.
Packit 549fdc
Packit 549fdc
@float Figure,fig-gnutls-handshake-sequence
Packit 549fdc
@image{gnutls-handshake-sequence,12cm}
Packit 549fdc
@caption{GnuTLS handshake process sequence.}
Packit 549fdc
@end float
Packit 549fdc
Packit 549fdc
@node TLS Authentication Methods
Packit 549fdc
@section TLS Authentication Methods
Packit 549fdc
In @acronym{GnuTLS} authentication methods can be implemented quite
Packit 549fdc
easily.  Since the required changes to add a new authentication method
Packit 549fdc
affect only the handshake protocol, a simple interface is used. An
Packit 549fdc
authentication method needs to implement the functions shown below.
Packit 549fdc
Packit 549fdc
@verbatim
Packit 549fdc
typedef struct 
Packit 549fdc
{
Packit 549fdc
  const char *name;
Packit 549fdc
  int (*gnutls_generate_server_certificate) (gnutls_session_t, gnutls_buffer_st*);
Packit 549fdc
  int (*gnutls_generate_client_certificate) (gnutls_session_t, gnutls_buffer_st*);
Packit 549fdc
  int (*gnutls_generate_server_kx) (gnutls_session_t, gnutls_buffer_st*);
Packit 549fdc
  int (*gnutls_generate_client_kx) (gnutls_session_t, gnutls_buffer_st*);
Packit 549fdc
  int (*gnutls_generate_client_cert_vrfy) (gnutls_session_t, gnutls_buffer_st *);
Packit 549fdc
  int (*gnutls_generate_server_certificate_request) (gnutls_session_t,
Packit 549fdc
                                                     gnutls_buffer_st *);
Packit 549fdc
Packit 549fdc
  int (*gnutls_process_server_certificate) (gnutls_session_t, opaque *,
Packit 549fdc
                                            size_t);
Packit 549fdc
  int (*gnutls_process_client_certificate) (gnutls_session_t, opaque *,
Packit 549fdc
                                            size_t);
Packit 549fdc
  int (*gnutls_process_server_kx) (gnutls_session_t, opaque *, size_t);
Packit 549fdc
  int (*gnutls_process_client_kx) (gnutls_session_t, opaque *, size_t);
Packit 549fdc
  int (*gnutls_process_client_cert_vrfy) (gnutls_session_t, opaque *, size_t);
Packit 549fdc
  int (*gnutls_process_server_certificate_request) (gnutls_session_t,
Packit 549fdc
                                                    opaque *, size_t);
Packit 549fdc
} mod_auth_st;
Packit 549fdc
@end verbatim
Packit 549fdc
Packit 549fdc
Those functions are responsible for the
Packit 549fdc
interpretation of the handshake protocol messages. It is common for such
Packit 549fdc
functions to read data from one or more @code{credentials_t}
Packit 549fdc
structures@footnote{such as the
Packit 549fdc
@code{gnutls_certificate_credentials_t} structures} and write data,
Packit 549fdc
such as certificates, usernames etc. to @code{auth_info_t} structures.
Packit 549fdc
Packit 549fdc
Packit 549fdc
Simple examples of existing authentication methods can be seen in
Packit 549fdc
@code{auth/@-psk.c} for PSK ciphersuites and @code{auth/@-srp.c} for SRP
Packit 549fdc
ciphersuites. After implementing these functions the structure holding
Packit 549fdc
its pointers has to be registered in @code{gnutls_@-algorithms.c} in the
Packit 549fdc
@code{_gnutls_@-kx_@-algorithms} structure.
Packit 549fdc
Packit 549fdc
@node TLS Extension Handling
Packit 549fdc
@section TLS Extension Handling
Packit 549fdc
As with authentication methods, the TLS extensions handlers can be
Packit 549fdc
implemented using the interface shown below.
Packit 549fdc
Packit 549fdc
@verbatim
Packit 549fdc
typedef int (*gnutls_ext_recv_func) (gnutls_session_t session,
Packit 549fdc
                                     const unsigned char *data, size_t len);
Packit 549fdc
typedef int (*gnutls_ext_send_func) (gnutls_session_t session,
Packit 549fdc
                                     gnutls_buffer_st *extdata);
Packit 549fdc
@end verbatim
Packit 549fdc
Packit 549fdc
Here there are two functions, one for receiving the extension data
Packit 549fdc
and one for sending. These functions have to check internally whether
Packit 549fdc
they operate in client or server side. 
Packit 549fdc
Packit 549fdc
A simple example of an extension handler can be seen in
Packit 549fdc
@code{ext/@-srp.c} in GnuTLS' source code. After implementing these functions, 
Packit 549fdc
together with the extension number they handle, they have to be registered 
Packit 549fdc
using @funcintref{_gnutls_ext_register} in
Packit 549fdc
@code{gnutls_extensions.c} typically within @funcintref{_gnutls_ext_init}.
Packit 549fdc
Packit 549fdc
@subheading Adding a new TLS extension
Packit 549fdc
Packit 549fdc
Adding support for a new TLS extension is done from time to time, and
Packit 549fdc
the process to do so is not difficult.  Here are the steps you need to
Packit 549fdc
follow if you wish to do this yourself.  For sake of discussion, let's
Packit 549fdc
consider adding support for the hypothetical TLS extension
Packit 549fdc
@code{foobar}. The following section is about adding an extension to GnuTLS,
Packit 549fdc
for custom application extensions you should check the exported functions
Packit 549fdc
@funcref{gnutls_session_ext_register} or @funcref{gnutls_ext_register}.
Packit 549fdc
Packit 549fdc
@subsubheading Add @code{configure} option like @code{--enable-foobar} or @code{--disable-foobar}.
Packit 549fdc
Packit 549fdc
This step is useful when the extension code is large and it might be desirable
Packit 549fdc
to disable the extension under some circumstances. Otherwise it can be safely
Packit 549fdc
skipped.
Packit 549fdc
Packit 549fdc
Whether to chose enable or disable depends on whether you intend to make the extension be
Packit 549fdc
enabled by default.  Look at existing checks (i.e., SRP, authz) for
Packit 549fdc
how to model the code.  For example:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
AC_MSG_CHECKING([whether to disable foobar support])
Packit 549fdc
AC_ARG_ENABLE(foobar,
Packit 549fdc
	AS_HELP_STRING([--disable-foobar],
Packit 549fdc
		[disable foobar support]),
Packit 549fdc
	ac_enable_foobar=no)
Packit 549fdc
if test x$ac_enable_foobar != xno; then
Packit 549fdc
 AC_MSG_RESULT(no)
Packit 549fdc
 AC_DEFINE(ENABLE_FOOBAR, 1, [enable foobar])
Packit 549fdc
else
Packit 549fdc
 ac_full=0
Packit 549fdc
 AC_MSG_RESULT(yes)
Packit 549fdc
fi
Packit 549fdc
AM_CONDITIONAL(ENABLE_FOOBAR, test "$ac_enable_foobar" != "no")
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
These lines should go in @code{m4/hooks.m4}.
Packit 549fdc
Packit 549fdc
@subsubheading Add IANA extension value to @code{extensions_t} in @code{gnutls_int.h}.
Packit 549fdc
Packit 549fdc
A good name for the value would be GNUTLS_EXTENSION_FOOBAR.  Check
Packit 549fdc
with @url{http://www.iana.org/assignments/tls-extensiontype-values}
Packit 549fdc
for allocated values.  For experiments, you could pick a number but
Packit 549fdc
remember that some consider it a bad idea to deploy such modified
Packit 549fdc
version since it will lead to interoperability problems in the future
Packit 549fdc
when the IANA allocates that number to someone else, or when the
Packit 549fdc
foobar protocol is allocated another number.
Packit 549fdc
Packit 549fdc
@subsubheading Add an entry to @code{_gnutls_extensions} in @code{gnutls_extensions.c}.
Packit 549fdc
Packit 549fdc
A typical entry would be:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
  int ret;
Packit 549fdc
Packit 549fdc
#if ENABLE_FOOBAR
Packit 549fdc
  ret = _gnutls_ext_register (&foobar_ext);
Packit 549fdc
  if (ret != GNUTLS_E_SUCCESS)
Packit 549fdc
    return ret;
Packit 549fdc
#endif
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
Most likely you'll need to add an @code{#include "ext/@-foobar.h"}, that
Packit 549fdc
will contain something like
Packit 549fdc
like:
Packit 549fdc
@example
Packit 549fdc
  extension_entry_st foobar_ext = @{
Packit 549fdc
    .name = "FOOBAR",
Packit 549fdc
    .type = GNUTLS_EXTENSION_FOOBAR,
Packit 549fdc
    .parse_type = GNUTLS_EXT_TLS,
Packit 549fdc
    .recv_func = _foobar_recv_params,
Packit 549fdc
    .send_func = _foobar_send_params,
Packit 549fdc
    .pack_func = _foobar_pack,
Packit 549fdc
    .unpack_func = _foobar_unpack,
Packit 549fdc
    .deinit_func = NULL
Packit 549fdc
  @}
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
The GNUTLS_EXTENSION_FOOBAR is the integer value you added to
Packit 549fdc
@code{gnutls_int.h} earlier.  In this structure you specify the
Packit 549fdc
functions to read the extension from the hello message, the function
Packit 549fdc
to send the reply to, and two more functions to pack and unpack from
Packit 549fdc
stored session data (e.g. when resumming a session). The @code{deinit} function
Packit 549fdc
will be called to deinitialize the extension's private parameters, if any.
Packit 549fdc
Packit 549fdc
Note that the conditional @code{ENABLE_FOOBAR} definition should only be 
Packit 549fdc
used if step 1 with the @code{configure} options has taken place.
Packit 549fdc
Packit 549fdc
@subsubheading Add new files that implement the extension.
Packit 549fdc
Packit 549fdc
The functions you are responsible to add are those mentioned in the
Packit 549fdc
previous step.  They should be added in a file such as @code{ext/@-foobar.c} 
Packit 549fdc
and headers should be placed in @code{ext/@-foobar.h}.
Packit 549fdc
As a starter, you could add this:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
int
Packit 549fdc
_foobar_recv_params (gnutls_session_t session, const opaque * data,
Packit 549fdc
                     size_t data_size)
Packit 549fdc
@{
Packit 549fdc
  return 0;
Packit 549fdc
@}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_foobar_send_params (gnutls_session_t session, gnutls_buffer_st* data)
Packit 549fdc
@{
Packit 549fdc
  return 0;
Packit 549fdc
@}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_foobar_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
Packit 549fdc
@{
Packit 549fdc
   /* Append the extension's internal state to buffer */
Packit 549fdc
   return 0;
Packit 549fdc
@}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_foobar_unpack (gnutls_buffer_st * ps, extension_priv_data_t * epriv)
Packit 549fdc
@{
Packit 549fdc
   /* Read the internal state from buffer */
Packit 549fdc
   return 0;
Packit 549fdc
@}
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
The @funcintref{_foobar_recv_params} function is responsible for
Packit 549fdc
parsing incoming extension data (both in the client and server).
Packit 549fdc
Packit 549fdc
The @funcintref{_foobar_send_params} function is responsible for
Packit 549fdc
sending extension data (both in the client and server). It should
Packit 549fdc
append data to provided buffer and return a positive (or zero) number on
Packit 549fdc
success or a negative error code. Previous to 3.6.0 versions of GnuTLS required
Packit 549fdc
that function to return the number of bytes that were written. If zero
Packit 549fdc
is returned and no bytes are appended the extension will not be sent.
Packit 549fdc
If a zero byte extension is to be sent this function must return
Packit 549fdc
@code{GNUTLS_E_INT_RET_0}.
Packit 549fdc
Packit 549fdc
If you receive length fields that don't match, return
Packit 549fdc
@code{GNUTLS_E_@-UNEXPECTED_@-PACKET_@-LENGTH}.  If you receive invalid
Packit 549fdc
data, return @code{GNUTLS_E_@-RECEIVED_@-ILLEGAL_@-PARAMETER}.  You can use
Packit 549fdc
other error codes from the list in @ref{Error codes}.  Return 0 on success.
Packit 549fdc
Packit 549fdc
An extension typically stores private information in the @code{session}
Packit 549fdc
data for later usage. That can be done using the functions 
Packit 549fdc
@funcintref{_gnutls_ext_set_session_data} and
Packit 549fdc
@funcintref{_gnutls_ext_get_session_data}. You can check simple examples
Packit 549fdc
at @code{ext/@-max_@-record.c} and @code{ext/@-server_@-name.c} extensions.
Packit 549fdc
That private information can be saved and restored across session 
Packit 549fdc
resumption if the following functions are set:
Packit 549fdc
Packit 549fdc
The @funcintref{_foobar_pack} function is responsible for packing
Packit 549fdc
internal extension data to save them in the session resumption storage.
Packit 549fdc
Packit 549fdc
The @funcintref{_foobar_unpack} function is responsible for
Packit 549fdc
restoring session data from the session resumption storage.
Packit 549fdc
Packit 549fdc
Recall that both the client and server, send and receive
Packit 549fdc
parameters, and your code most likely will need to do different things
Packit 549fdc
depending on which mode it is in.  It may be useful to make this
Packit 549fdc
distinction explicit in the code.  Thus, for example, a better
Packit 549fdc
template than above would be:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
int
Packit 549fdc
_gnutls_foobar_recv_params (gnutls_session_t session,
Packit 549fdc
                            const opaque * data,
Packit 549fdc
                            size_t data_size)
Packit 549fdc
@{
Packit 549fdc
  if (session->security_parameters.entity == GNUTLS_CLIENT)
Packit 549fdc
    return foobar_recv_client (session, data, data_size);
Packit 549fdc
  else
Packit 549fdc
    return foobar_recv_server (session, data, data_size);
Packit 549fdc
@}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_gnutls_foobar_send_params (gnutls_session_t session,
Packit 549fdc
                            gnutls_buffer_st * data)
Packit 549fdc
@{
Packit 549fdc
  if (session->security_parameters.entity == GNUTLS_CLIENT)
Packit 549fdc
    return foobar_send_client (session, data);
Packit 549fdc
  else
Packit 549fdc
    return foobar_send_server (session, data);
Packit 549fdc
@}
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
The functions used would be declared as @code{static} functions, of
Packit 549fdc
the appropriate prototype, in the same file.
Packit 549fdc
When adding the files, you'll need to add them to @code{ext/@-Makefile.am}
Packit 549fdc
as well, for example:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
if ENABLE_FOOBAR
Packit 549fdc
libgnutls_ext_la_SOURCES += ext/foobar.c ext/foobar.h
Packit 549fdc
endif
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
@subsubheading Add API functions to enable/disable the extension.
Packit 549fdc
Packit 549fdc
It might be desirable to allow users of the extension to
Packit 549fdc
request use of the extension, or set extension specific data.  
Packit 549fdc
This can be implemented by adding extension specific function calls
Packit 549fdc
that can be added to @code{includes/@-gnutls/@-gnutls.h},
Packit 549fdc
as long as the LGPLv2.1+ applies.
Packit 549fdc
The implementation of the function should lie in the @code{ext/@-foobar.c} file.
Packit 549fdc
Packit 549fdc
To make the API available in the shared library you need to add the
Packit 549fdc
symbol in @code{lib/@-libgnutls.map}, so that the symbol
Packit 549fdc
is exported properly.
Packit 549fdc
Packit 549fdc
When writing GTK-DOC style documentation for your new APIs, don't
Packit 549fdc
forget to add @code{Since:} tags to indicate the GnuTLS version the
Packit 549fdc
API was introduced in.
Packit 549fdc
Packit 549fdc
@subsubheading Heartbeat extension.
Packit 549fdc
Packit 549fdc
One such extension is HeartBeat protocol (RFC6520:
Packit 549fdc
@url{https://tools.ietf.org/html/rfc6520}) implementation. To enable
Packit 549fdc
it use option --heartbeat with example client and server supplied with
Packit 549fdc
gnutls:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
./doc/credentials/gnutls-http-serv --priority "NORMAL:-CIPHER-ALL:+NULL" -d 100 \
Packit 549fdc
    --heartbeat --echo
Packit 549fdc
./src/gnutls-cli --priority "NORMAL:-CIPHER-ALL:+NULL" -d 100 localhost -p 5556 \
Packit 549fdc
    --insecure --heartbeat
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
After that pasting
Packit 549fdc
@example
Packit 549fdc
**HEARTBEAT**
Packit 549fdc
@end example
Packit 549fdc
command into gnutls-cli will trigger corresponding command on the server and it will send HeartBeat Request with random length to client.
Packit 549fdc
Packit 549fdc
Another way is to run capabilities check with:
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
./doc/credentials/gnutls-http-serv -d 100 --heartbeat
Packit 549fdc
./src/gnutls-cli-debug localhost -p 5556
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
@subheading Adding a new Supplemental Data Handshake Message
Packit 549fdc
Packit 549fdc
TLS handshake extensions allow to send so called supplemental data
Packit 549fdc
handshake messages @xcite{RFC4680}. This short section explains how to 
Packit 549fdc
implement a supplemental data handshake message for a given TLS extension.
Packit 549fdc
Packit 549fdc
First of all, modify your extension @code{foobar} in the way, to instruct
Packit 549fdc
the handshake process to send and receive supplemental data, as shown below.
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
int
Packit 549fdc
_gnutls_foobar_recv_params (gnutls_session_t session, const opaque * data,
Packit 549fdc
                                 size_t _data_size)
Packit 549fdc
@{
Packit 549fdc
   ...
Packit 549fdc
   gnutls_supplemental_recv(session, 1);
Packit 549fdc
   ...
Packit 549fdc
@}
Packit 549fdc
Packit 549fdc
int
Packit 549fdc
_gnutls_foobar_send_params (gnutls_session_t session, gnutls_buffer_st *extdata)
Packit 549fdc
@{
Packit 549fdc
   ...
Packit 549fdc
   gnutls_supplemental_send(session, 1);
Packit 549fdc
   ...
Packit 549fdc
@}
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
Furthermore you'll need two new functions @funcintref{_foobar_supp_recv_params}
Packit 549fdc
and @funcintref{_foobar_supp_send_params}, which must conform to the following 
Packit 549fdc
prototypes.
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
typedef int (*gnutls_supp_recv_func)(gnutls_session_t session,
Packit 549fdc
                                     const unsigned char *data,
Packit 549fdc
                                     size_t data_size);
Packit 549fdc
typedef int (*gnutls_supp_send_func)(gnutls_session_t session,
Packit 549fdc
                                     gnutls_buffer_t buf);
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
The following example code shows how to send a
Packit 549fdc
``Hello World'' string in the supplemental data handshake message.
Packit 549fdc
Packit 549fdc
@example
Packit 549fdc
int 
Packit 549fdc
_foobar_supp_recv_params(gnutls_session_t session, const opaque *data, size_t _data_size)
Packit 549fdc
@{
Packit 549fdc
   uint8_t len = _data_size;
Packit 549fdc
   unsigned char *msg;
Packit 549fdc
Packit 549fdc
   msg = gnutls_malloc(len);
Packit 549fdc
   if (msg == NULL) return GNUTLS_E_MEMORY_ERROR;
Packit 549fdc
Packit 549fdc
   memcpy(msg, data, len);
Packit 549fdc
   msg[len]='\0';
Packit 549fdc
Packit 549fdc
   /* do something with msg */
Packit 549fdc
   gnutls_free(msg);
Packit 549fdc
Packit 549fdc
   return len;
Packit 549fdc
@}
Packit 549fdc
Packit 549fdc
int 
Packit 549fdc
_foobar_supp_send_params(gnutls_session_t session, gnutls_buffer_t buf)
Packit 549fdc
@{
Packit 549fdc
   unsigned char *msg = "hello world";
Packit 549fdc
   int len = strlen(msg);
Packit 549fdc
Packit 549fdc
   if (gnutls_buffer_append_data(buf, msg, len) < 0)
Packit 549fdc
       abort();
Packit 549fdc
Packit 549fdc
   return len;
Packit 549fdc
@}
Packit 549fdc
@end example
Packit 549fdc
Packit 549fdc
Afterwards, register the new supplemental data using @funcref{gnutls_session_supplemental_register},
Packit 549fdc
or @funcref{gnutls_supplemental_register} at some point in your program.
Packit 549fdc
Packit 549fdc
@node Cryptographic Backend
Packit 549fdc
@section Cryptographic Backend
Packit 549fdc
Packit 549fdc
Today most new processors, either for embedded or desktop systems
Packit 549fdc
include either instructions  intended to speed up cryptographic operations,
Packit 549fdc
or a co-processor with cryptographic capabilities. Taking advantage of 
Packit 549fdc
those is a challenging task for every cryptographic  application or 
Packit 549fdc
library. GnuTLS handles the cryptographic provider in a modular
Packit 549fdc
way, following a layered approach to access
Packit 549fdc
cryptographic operations as in @ref{fig-crypto-layers}.
Packit 549fdc
Packit 549fdc
@float Figure,fig-crypto-layers
Packit 549fdc
@image{gnutls-crypto-layers,12cm}
Packit 549fdc
@caption{GnuTLS cryptographic back-end design.}
Packit 549fdc
@end float
Packit 549fdc
Packit 549fdc
The TLS layer uses a cryptographic provider layer, that will in turn either 
Packit 549fdc
use the default crypto provider -- a software crypto library, or use an external
Packit 549fdc
crypto provider, if available in the local system. The reason of handling
Packit 549fdc
the external cryptographic provider in GnuTLS and not delegating it to
Packit 549fdc
the cryptographic libraries, is that none of the supported cryptographic
Packit 549fdc
libraries support @code{/dev/crypto} or CPU-optimized cryptography in
Packit 549fdc
an efficient way.
Packit 549fdc
Packit 549fdc
@subheading Cryptographic library layer
Packit 549fdc
The Cryptographic library layer, currently supports only
Packit 549fdc
libnettle. Older versions of GnuTLS used to support libgcrypt,
Packit 549fdc
but it was switched with nettle mainly for performance reasons@footnote{See
Packit 549fdc
@url{http://lists.gnu.org/archive/html/gnutls-devel/2011-02/msg00079.html}.}
Packit 549fdc
and secondary because it is a simpler library to use.
Packit 549fdc
In the future other cryptographic libraries might be supported as well.
Packit 549fdc
Packit 549fdc
@subheading External cryptography provider
Packit 549fdc
Systems that include a cryptographic co-processor, typically come with
Packit 549fdc
kernel drivers to utilize the operations from software. For this reason 
Packit 549fdc
GnuTLS provides a layer where each individual algorithm used can be replaced
Packit 549fdc
by another implementation, i.e., the one provided by the driver. The
Packit 549fdc
FreeBSD, OpenBSD and Linux kernels@footnote{Check @url{http://home.gna.org/cryptodev-linux/} 
Packit 549fdc
for the Linux kernel implementation of @code{/dev/crypto}.} include already 
Packit 549fdc
a number of hardware assisted implementations, and also provide an interface 
Packit 549fdc
to access them, called @code{/dev/crypto}.
Packit 549fdc
GnuTLS will take advantage of this interface if compiled with special
Packit 549fdc
options. That is because in most systems where hardware-assisted 
Packit 549fdc
cryptographic operations are not available, using this interface might 
Packit 549fdc
actually harm performance.
Packit 549fdc
Packit 549fdc
In systems that include cryptographic instructions with the CPU's
Packit 549fdc
instructions set, using the kernel interface will introduce an
Packit 549fdc
unneeded layer. For this reason GnuTLS includes such optimizations
Packit 549fdc
found in popular processors such as the AES-NI or VIA PADLOCK instruction sets.
Packit 549fdc
This is achieved using a mechanism that detects CPU capabilities and
Packit 549fdc
overrides parts of crypto back-end at runtime.
Packit 549fdc
The next section discusses the registration of a detected algorithm
Packit 549fdc
optimization. For more information please consult the @acronym{GnuTLS}
Packit 549fdc
source code in @code{lib/accelerated/}.
Packit 549fdc
Packit 549fdc
@subsubheading Overriding specific algorithms
Packit 549fdc
When an optimized implementation of a single algorithm is available,
Packit 549fdc
say a hardware assisted version of @acronym{AES-CBC} then the
Packit 549fdc
following functions, from @code{crypto.h}, can 
Packit 549fdc
be used to register those algorithms.
Packit 549fdc
Packit 549fdc
@itemize
Packit 549fdc
Packit 549fdc
@item @funcref{gnutls_crypto_register_cipher}:
Packit 549fdc
To register a cipher algorithm.
Packit 549fdc
Packit 549fdc
@item @funcref{gnutls_crypto_register_aead_cipher}:
Packit 549fdc
To register an AEAD cipher algorithm.
Packit 549fdc
Packit 549fdc
@item @funcref{gnutls_crypto_register_mac}:
Packit 549fdc
To register a MAC algorithm.
Packit 549fdc
Packit 549fdc
@item @funcref{gnutls_crypto_register_digest}:
Packit 549fdc
To register a hash algorithm.
Packit 549fdc
Packit 549fdc
@end itemize
Packit 549fdc
Packit 549fdc
Those registration functions will only replace the specified algorithm
Packit 549fdc
and leave the rest of subsystem intact.
Packit 549fdc
Packit 549fdc
Packit 549fdc
@subheading Protecting keys through isolation
Packit 549fdc
Packit 549fdc
For asymmetric or public keys, GnuTLS supports PKCS #11 which allows
Packit 549fdc
operation without access to long term keys, in addition to CPU offloading.
Packit 549fdc
For more information see @ref{Hardware security modules and abstract key types}.
Packit 549fdc
Packit 549fdc
Packit 549fdc
@node Random Number Generators-internals
Packit 549fdc
@section Random Number Generators
Packit 549fdc
Packit 549fdc
@subheading About the generators
Packit 549fdc
Packit 549fdc
GnuTLS provides two random generators. The default, and the AES-DRBG random
Packit 549fdc
generator which is only used when the library is compiled with support for
Packit 549fdc
FIPS140-2 and the system is in FIPS140-2 mode.
Packit 549fdc
Packit 549fdc
@subheading The default generator - inner workings
Packit 549fdc
Packit 549fdc
The random number generator levels in @code{gnutls_rnd_level_t} map to two CHACHA-based random generators which
Packit 549fdc
are initially seeded using the OS random device, e.g., @code{/dev/urandom}
Packit 549fdc
or @code{getrandom()}. These random generators are unique per thread, and
Packit 549fdc
are automatically re-seeded when a fork is detected.
Packit 549fdc
Packit 549fdc
The reason the CHACHA cipher was selected for the GnuTLS' PRNG is the fact
Packit 549fdc
that CHACHA is considered a secure and fast stream cipher, and is already
Packit 549fdc
defined for use in TLS protocol. As such, the utilization of it would
Packit 549fdc
not stress the CPU caches, and would allow for better performance on busy
Packit 549fdc
servers, irrespective of their architecture (e.g., even if AES is not
Packit 549fdc
available with an optimized instruction set).
Packit 549fdc
Packit 549fdc
The generators are unique per thread to allow lock-free operation. That
Packit 549fdc
induces a cost of around 140-bytes for the state of the generators per
Packit 549fdc
thread, on threads that would utilize @funcref{gnutls_rnd}. At the same time
Packit 549fdc
it allows fast and lock-free access to the generators. The lock-free access
Packit 549fdc
benefits servers which utilize more than 4 threads, while imposes no cost on
Packit 549fdc
single threaded processes.
Packit 549fdc
Packit 549fdc
On the first call to @funcref{gnutls_rnd} the generators are seeded with two independent
Packit 549fdc
keys obtained from the OS random device. Their seed is used to output a fixed amount
Packit 549fdc
of bytes before re-seeding; the number of bytes output varies per generator.
Packit 549fdc
Packit 549fdc
One generator is dedicated for the @code{GNUTLS_RND_NONCE} level, and the
Packit 549fdc
second is shared for the @code{GNUTLS_RND_KEY} and @code{GNUTLS_RND_RANDOM}
Packit 549fdc
levels. For the rest of this section we refer to the first as the nonce
Packit 549fdc
generator and the second as the key generator.
Packit 549fdc
Packit 549fdc
The nonce generator will reseed after outputing a fixed amount of bytes
Packit 549fdc
(typically few megabytes), or after few hours of operation without reaching
Packit 549fdc
the limit has passed. It is being re-seed using
Packit 549fdc
the key generator to obtain a new key for the CHACHA cipher, which is mixed
Packit 549fdc
with its old one.
Packit 549fdc
Packit 549fdc
Similarly, the key generator, will also re-seed after a fixed amount
Packit 549fdc
of bytes is generated (typically less than the nonce), and will also re-seed
Packit 549fdc
based on time, i.e., after few hours of operation without reaching the limit
Packit 549fdc
for a re-seed. For its re-seed it mixes mixes data obtained from the OS random
Packit 549fdc
device with the previous key.
Packit 549fdc
Packit 549fdc
Although the key generator used to provide data for the @code{GNUTLS_RND_RANDOM}
Packit 549fdc
and @code{GNUTLS_RND_KEY} levels is identical, when used with the @code{GNUTLS_RND_KEY} level
Packit 549fdc
a re-key of the PRNG using its own output, is additionally performed. That ensures that
Packit 549fdc
the recovery of the PRNG state will not be sufficient to recover previously generated values.
Packit 549fdc
Packit 549fdc
Packit 549fdc
@subheading The AES-DRBG generator - inner workings
Packit 549fdc
Packit 549fdc
Similar with the default generator, the random number generator levels in @code{gnutls_rnd_level_t} map to two
Packit 549fdc
AES-DRBG random generators which are initially seeded using the OS random device,
Packit 549fdc
e.g., @code{/dev/urandom} or @code{getrandom()}. These random generators are
Packit 549fdc
unique per thread, and are automatically re-seeded when a fork is detected.
Packit 549fdc
Packit 549fdc
The AES-DRBG generator is based on the AES cipher in counter mode and is
Packit 549fdc
re-seeded after a fixed amount of bytes are generated.
Packit 549fdc
Packit 549fdc
Packit 549fdc
@subheading Defense against PRNG attacks
Packit 549fdc
Packit 549fdc
This section describes the counter-measures available in the Pseudo-random number generator (PRNG)
Packit 549fdc
of GnuTLS for known attacks as described in @xcite{PRNGATTACKS}. Note that, the attacks on a PRNG such as
Packit 549fdc
state-compromise, assume a quite powerful adversary which has in practice
Packit 549fdc
access to the PRNG state.
Packit 549fdc
Packit 549fdc
@subsubheading Cryptanalytic
Packit 549fdc
Packit 549fdc
To defend against cryptanalytic attacks GnuTLS' PRNG is a stream cipher
Packit 549fdc
designed to defend against the same attacks. As such, GnuTLS' PRNG strength
Packit 549fdc
with regards to this attack relies on the underlying crypto block,
Packit 549fdc
which at the time of writing is CHACHA. That is easily replaceable in
Packit 549fdc
the future if attacks are found to be possible in that cipher.
Packit 549fdc
Packit 549fdc
@subsubheading Input-based attacks
Packit 549fdc
Packit 549fdc
These attacks assume that the attacker can influence the input that is used
Packit 549fdc
to form the state of the PRNG. To counter these attacks GnuTLS does not
Packit 549fdc
gather input from the system environment but rather relies on the OS
Packit 549fdc
provided random generator. That is the @code{/dev/urandom} or
Packit 549fdc
@code{getentropy}/@code{getrandom} system calls. As such, GnuTLS' PRNG
Packit 549fdc
is as strong as the system random generator can assure with regards to
Packit 549fdc
input-based attacks.
Packit 549fdc
Packit 549fdc
@subsubheading State-compromise: Backtracking
Packit 549fdc
Packit 549fdc
A backtracking attack, assumes that an adversary obtains at some point of time
Packit 549fdc
access to the generator state, and wants to recover past bytes. As the
Packit 549fdc
GnuTLS generator is fine-tuned to provide multiple levels, such an attack
Packit 549fdc
mainly concerns levels @code{GNUTLS_RND_RANDOM} and @code{GNUTLS_RND_KEY},
Packit 549fdc
since @code{GNUTLS_RND_NONCE} is intended to output non-secret data.
Packit 549fdc
The @code{GNUTLS_RND_RANDOM} generator at the time of writing can output
Packit 549fdc
2MB prior to being re-seeded thus this is its upper bound for previously
Packit 549fdc
generated data recovered using this attack. That assumes that the state
Packit 549fdc
of the operating system random generator is unknown to the attacker, and we carry that
Packit 549fdc
assumption on the next paragraphs. The usage of @code{GNUTLS_RND_KEY} level
Packit 549fdc
ensures that no backtracking is possible for all output data, by re-keying
Packit 549fdc
the PRNG using its own output.
Packit 549fdc
Packit 549fdc
Such an attack reflects the real world scenario where application's memory is
Packit 549fdc
temporarily compromised, while the kernel's memory is inaccessible.
Packit 549fdc
Packit 549fdc
@subsubheading State-compromise: Permanent Compromise Attack
Packit 549fdc
Packit 549fdc
A permanent compromise attack implies that once an attacker compromises the
Packit 549fdc
state of GnuTLS' random generator at a specific time, future and past
Packit 549fdc
outputs from the generator are compromised. For past outputs the
Packit 549fdc
previous paragraph applies. For future outputs, both the @code{GNUTLS_RND_RANDOM}
Packit 549fdc
and the @code{GNUTLS_RND_KEY} will recover after 2MB of data have been generated
Packit 549fdc
or few hours have passed (two at the time of writing). Similarly the @code{GNUTLS_RND_NONCE}
Packit 549fdc
level generator will recover after several megabytes of output is generated,
Packit 549fdc
or its re-key time is reached.
Packit 549fdc
Packit 549fdc
@subsubheading State-compromise: Iterative guessing
Packit 549fdc
Packit 549fdc
This attack assumes that after an attacker obtained the PRNG state
Packit 549fdc
at some point, is able to recover the state at a later time by observing
Packit 549fdc
outputs of the PRNG. That is countered by switching the key to generators
Packit 549fdc
using a combination of a fresh key and the old one (using XOR), at
Packit 549fdc
re-seed time. All levels are immune to such attack after a re-seed.
Packit 549fdc
Packit 549fdc
@subsubheading State-compromise: Meet-in-the-Middle
Packit 549fdc
Packit 549fdc
This attack assumes that the attacker obtained the PRNG state at
Packit 549fdc
two distinct times, and being able to recover the state at the third time
Packit 549fdc
after observing the output of the PRNG. Given the approach described
Packit 549fdc
on the above paragraph, all levels are immune to such attack.
Packit 549fdc
Packit 549fdc
@node FIPS140-2 mode
Packit 549fdc
@section FIPS140-2 mode
Packit 549fdc
Packit 549fdc
GnuTLS can operate in a special mode for FIPS140-2. That mode of operation
Packit 549fdc
is for the conformance to NIST's FIPS140-2 publication, which consists of policies
Packit 549fdc
for cryptographic modules (such as software libraries). Its implementation in
Packit 549fdc
GnuTLS is designed for Red Hat Enterprise Linux, and can only be enabled
Packit 549fdc
when the library is explicitly compiled with the '--enable-fips140-mode'
Packit 549fdc
configure option. The operation of the library is then modified, as follows.
Packit 549fdc
Packit 549fdc
@itemize
Packit 549fdc
@item FIPS140-2 mode is enabled when @code{/proc/sys/crypto/fips_enabled} contains '1' and @code{/etc/system-fips} is present.
Packit 549fdc
@item Only approved by FIPS140-2 algorithms are enabled
Packit 549fdc
@item Only approved by FIPS140-2 key lengths are allowed for key generation
Packit 549fdc
@item The random generator used switches to DRBG-AES
Packit 549fdc
@item The integrity of the GnuTLS and dependent libraries is checked on startup
Packit 549fdc
@item Algorithm self-tests are run on library load
Packit 549fdc
@item Any cryptographic operation will be refused if any of the self-tests failed
Packit 549fdc
@end itemize
Packit 549fdc
Packit 549fdc
There is a 'zombie' FIPS140-2 mode which is enabled when only one of the files
Packit 549fdc
described in the first step is available. In that case the self tests will
Packit 549fdc
be performed without affecting the operation of the library.
Packit 549fdc
Packit 549fdc
The integrity checks for the dependent libraries and GnuTLS are performed
Packit 549fdc
using '.hmac' files which are present at the same path as the library. The
Packit 549fdc
key for the operations can be provided on compile-time with the configure
Packit 549fdc
option '--with-fips140-key'. The MAC algorithm used is HMAC-SHA256.
Packit 549fdc
Packit 549fdc
There are also few environment variables which modify that operation. The
Packit 549fdc
environment variable @code{GNUTLS_SKIP_FIPS_INTEGRITY_CHECKS} will disable
Packit 549fdc
the library integrity tests on startup, and the variable
Packit 549fdc
@code{GNUTLS_FORCE_FIPS_MODE} when set to '1' will enable the FIPS140-2
Packit 549fdc
mode, when set to '0' will force a disable of it.
Packit 549fdc
Packit 549fdc
On runtime an application can verify whether the library is in FIPS140-2
Packit 549fdc
using the @funcref{gnutls_fips140_mode_enabled} function.