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