This is gnutls.info, produced by makeinfo version 6.3 from gnutls.texi.

This manual is last updated 23 March 2015 for version 3.3.29 of GnuTLS.

Copyright (C) 2001-2013 Free Software Foundation, Inc.\\ Copyright (C)
2001-2013 Nikos Mavrogiannopoulos

     Permission is granted to copy, distribute and/or modify this
     document under the terms of the GNU Free Documentation License,
     Version 1.3 or any later version published by the Free Software
     Foundation; with no Invariant Sections, no Front-Cover Texts, and
     no Back-Cover Texts.  A copy of the license is included in the
     section entitled "GNU Free Documentation License".
INFO-DIR-SECTION Software libraries
START-INFO-DIR-ENTRY
* GnuTLS: (gnutls).		GNU Transport Layer Security Library.
END-INFO-DIR-ENTRY

INFO-DIR-SECTION System Administration
START-INFO-DIR-ENTRY
* certtool: (gnutls)Invoking certtool.	Manipulate certificates and keys.
* gnutls-serv: (gnutls)Invoking gnutls-serv.	GnuTLS test server.
* gnutls-cli: (gnutls)Invoking gnutls-cli.	GnuTLS test client.
* gnutls-cli-debug: (gnutls)Invoking gnutls-cli-debug.	GnuTLS debug client.
* psktool: (gnutls)Invoking psktool.	Simple TLS-Pre-Shared-Keys manager.
* srptool: (gnutls)Invoking srptool.	Simple SRP password tool.
END-INFO-DIR-ENTRY


File: gnutls.info,  Node: Associating the credentials,  Next: Setting up the transport layer,  Prev: Session initialization,  Up: How to use GnuTLS in applications

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

* Menu:

* Certificate credentials::
* SRP credentials::
* PSK credentials::
* Anonymous credentials::

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

Authentication     Key exchange       Client         Server
method                                credentials    credentials
                                                     
--------------------------------------------------------------------
Certificate        'KX_RSA',          'CRD_CERTIFICATE''CRD_CERTIFICATE'
                   'KX_DHE_RSA',                     
                   'KX_DHE_DSS',
                   'KX_ECDHE_RSA',
                   'KX_ECDHE_ECDSA',
                   'KX_RSA_EXPORT'
Password and       'KX_SRP_RSA',      'CRD_SRP'      'CRD_CERTIFICATE',
certificate        'KX_SRP_DSS'                      'CRD_SRP'
                                                     
Password           'KX_SRP'           'CRD_SRP'      'CRD_SRP'
                                                     
Anonymous          'KX_ANON_DH',      'CRD_ANON'     'CRD_ANON'
                   'KX_ANON_ECDH'                    
Pre-shared key     'KX_PSK',          'CRD_PSK'      'CRD_PSK'
                   'KX_DHE_PSK',                     
                   'KX_ECDHE_PSK'

Table 6.2: Key exchange algorithms and the corresponding credential
types.


File: gnutls.info,  Node: Certificate credentials,  Next: SRP credentials,  Up: Associating the credentials

6.4.1 Certificates
------------------

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

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

'INT *note gnutls_certificate_allocate_credentials:: (gnutls_certificate_credentials_t * RES)'
'VOID *note gnutls_certificate_free_credentials:: (gnutls_certificate_credentials_t SC)'

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

'INT *note gnutls_certificate_set_x509_key_mem2:: (gnutls_certificate_credentials_t RES, const gnutls_datum_t * CERT, const gnutls_datum_t * KEY, gnutls_x509_crt_fmt_t TYPE, const char * PASS, unsigned int FLAGS)'
'INT *note gnutls_certificate_set_x509_key:: (gnutls_certificate_credentials_t RES, gnutls_x509_crt_t * CERT_LIST, int CERT_LIST_SIZE, gnutls_x509_privkey_t KEY)'
'INT *note gnutls_certificate_set_x509_key_file2:: (gnutls_certificate_credentials_t RES, const char * CERTFILE, const char * KEYFILE, gnutls_x509_crt_fmt_t TYPE, const char * PASS, unsigned int FLAGS)'

'INT *note gnutls_certificate_set_openpgp_key_mem:: (gnutls_certificate_credentials_t RES, const gnutls_datum_t * CERT, const gnutls_datum_t * KEY, gnutls_openpgp_crt_fmt_t FORMAT)'
'INT *note gnutls_certificate_set_openpgp_key:: (gnutls_certificate_credentials_t RES, gnutls_openpgp_crt_t CRT, gnutls_openpgp_privkey_t PKEY)'
'INT *note gnutls_certificate_set_openpgp_key_file:: (gnutls_certificate_credentials_t RES, const char * CERTFILE, const char * KEYFILE, gnutls_openpgp_crt_fmt_t FORMAT)'

Note however, that since functions like *note
gnutls_certificate_set_x509_key_file2:: may accept URLs that specify
objects stored in token, another important function is *note
gnutls_certificate_set_pin_function::.  That allows setting a callback
function to retrieve a PIN if the input keys are protected by PIN by the
token.

 -- Function: void gnutls_certificate_set_pin_function
          (gnutls_certificate_credentials_t CRED, gnutls_pin_callback_t
          FN, void * USERDATA)
     CRED: is a 'gnutls_certificate_credentials_t' structure.

     FN: A PIN callback

     USERDATA: Data to be passed in the callback

     This function will set a callback function to be used when required
     to access a protected object.  This function overrides any other
     global PIN functions.

     Note that this function must be called right after initialization
     to have effect.

     *Since:* 3.1.0

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

 -- Function: int gnutls_certificate_set_key
          (gnutls_certificate_credentials_t RES, const char ** NAMES,
          int NAMES_SIZE, gnutls_pcert_st * PCERT_LIST, int
          PCERT_LIST_SIZE, gnutls_privkey_t KEY)
     RES: is a 'gnutls_certificate_credentials_t' structure.

     NAMES: is an array of DNS name of the certificate (NULL if none)

     NAMES_SIZE: holds the size of the names list

     PCERT_LIST: contains a certificate list (path) for the specified
     private key

     PCERT_LIST_SIZE: holds the size of the certificate list

     KEY: is a 'gnutls_privkey_t' key

     This function sets a certificate/private key pair in the
     gnutls_certificate_credentials_t structure.  This function may be
     called more than once, in case multiple keys/certificates exist for
     the server.  For clients that wants to send more than its own end
     entity certificate (e.g., also an intermediate CA cert) then put
     the certificate chain in 'pcert_list' .

     Note that the 'key' and the elements of 'pcert_list' will become
     part of the credentials structure and must not be deallocated.
     They will be automatically deallocated when the 'res' structure is
     deinitialized.

     If that function fails to load the 'res' structure is at an
     undefined state, it must not be reused to load other keys or
     certificates.

     *Returns:* 'GNUTLS_E_SUCCESS' (0) on success, or a negative error
     code.

     *Since:* 3.0

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

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

'VOID *note gnutls_certificate_set_retrieve_function:: (gnutls_certificate_credentials_t CRED, gnutls_certificate_retrieve_function * FUNC)'
'VOID *note gnutls_certificate_set_retrieve_function2:: (gnutls_certificate_credentials_t CRED, gnutls_certificate_retrieve_function2 * FUNC)'
'INT *note gnutls_sign_algorithm_get_requested:: (gnutls_session_t SESSION, size_t INDX, gnutls_sign_algorithm_t * ALGO)'
c The functions above do not handle the requested server name
automatically.  A server would need to check the name requested by the
client using *note gnutls_server_name_get::, and serve the appropriate
certificate.  Note that some of these functions require the
'gnutls_pcert_st' structure to be filled in.  Helper functions to fill
in the structure are listed below.

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

'INT *note gnutls_pcert_import_x509:: (gnutls_pcert_st * PCERT, gnutls_x509_crt_t CRT, unsigned int FLAGS)'
'INT *note gnutls_pcert_import_openpgp:: (gnutls_pcert_st * PCERT, gnutls_openpgp_crt_t CRT, unsigned int FLAGS)'
'INT *note gnutls_pcert_import_x509_raw:: (gnutls_pcert_st * PCERT, const gnutls_datum_t * CERT, gnutls_x509_crt_fmt_t FORMAT, unsigned int FLAGS)'
'INT *note gnutls_pcert_import_openpgp_raw:: (gnutls_pcert_st * PCERT, const gnutls_datum_t * CERT, gnutls_openpgp_crt_fmt_t FORMAT, gnutls_openpgp_keyid_t KEYID, unsigned int FLAGS)'
'VOID *note gnutls_pcert_deinit:: (gnutls_pcert_st * PCERT)'

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

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

If a certificate is to be requested from the client during the
handshake, the server will send a certificate request message.  This
behavior is controlled *note gnutls_certificate_server_set_request::.
The request contains a list of the acceptable by the server certificate
signers.  This list is constructed using the trusted certificate
authorities of the server.  In cases where the server supports a large
number of certificate authorities it makes sense not to advertise all of
the names to save bandwidth.  That can be controlled using the function
*note gnutls_certificate_send_x509_rdn_sequence::.  This however will
have the side-effect of not restricting the client to certificates
signed by server's acceptable signers.

 -- Function: void gnutls_certificate_server_set_request
          (gnutls_session_t SESSION, gnutls_certificate_request_t REQ)
     SESSION: is a 'gnutls_session_t' structure.

     REQ: is one of GNUTLS_CERT_REQUEST, GNUTLS_CERT_REQUIRE

     This function specifies if we (in case of a server) are going to
     send a certificate request message to the client.  If 'req' is
     GNUTLS_CERT_REQUIRE then the server will return an error if the
     peer does not provide a certificate.  If you do not call this
     function then the client will not be asked to send a certificate.

 -- Function: void gnutls_certificate_send_x509_rdn_sequence
          (gnutls_session_t SESSION, int STATUS)
     SESSION: is a pointer to a 'gnutls_session_t' structure.

     STATUS: is 0 or 1

     If status is non zero, this function will order gnutls not to send
     the rdnSequence in the certificate request message.  That is the
     server will not advertise its trusted CAs to the peer.  If status
     is zero then the default behaviour will take effect, which is to
     advertise the server's trusted CAs.

     This function has no effect in clients, and in authentication
     methods other than certificate with X.509 certificates.

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

Certificate verification is possible by loading the trusted authorities
into the credentials structure by using the following functions,
applicable to X.509 and OpenPGP certificates.

'INT *note gnutls_certificate_set_x509_system_trust:: (gnutls_certificate_credentials_t CRED)'
'INT *note gnutls_certificate_set_x509_trust_file:: (gnutls_certificate_credentials_t CRED, const char * CAFILE, gnutls_x509_crt_fmt_t TYPE)'
'INT *note gnutls_certificate_set_openpgp_keyring_file:: (gnutls_certificate_credentials_t C, const char * FILE, gnutls_openpgp_crt_fmt_t FORMAT)'

The peer's certificate is not automatically verified and one must call
*note gnutls_certificate_verify_peers3:: after a successful handshake to
verify the certificate's signature and the owner of the certificate.
The verification status returned can be printed using *note
gnutls_certificate_verification_status_print::.

Alternatively the verification can occur during the handshake by using
*note gnutls_certificate_set_verify_function::.

The functions above provide a brief verification output.  If a detailed
output is required one should call *note gnutls_certificate_get_peers::
to obtain the raw certificate of the peer and verify it using the
functions discussed in *note X.509 certificates::.

 -- Function: int gnutls_certificate_verify_peers3 (gnutls_session_t
          SESSION, const char * HOSTNAME, unsigned int * STATUS)
     SESSION: is a gnutls session

     HOSTNAME: is the expected name of the peer; may be 'NULL'

     STATUS: is the output of the verification

     This function will verify the peer's certificate and store the
     status in the 'status' variable as a bitwise or'd
     gnutls_certificate_status_t values or zero if the certificate is
     trusted.  Note that value in 'status' is set only when the return
     value of this function is success (i.e, failure to trust a
     certificate does not imply a negative return value).  The default
     verification flags used by this function can be overridden using
     'gnutls_certificate_set_verify_flags()' .  See the documentation of
     'gnutls_certificate_verify_peers2()' for details in the
     verification process.

     If the 'hostname' provided is non-NULL then this function will
     compare the hostname in the certificate against the given.  The
     comparison will be accurate for ascii names; non-ascii names are
     compared byte-by-byte.  If names do not match the
     'GNUTLS_CERT_UNEXPECTED_OWNER' status flag will be set.

     In order to verify the purpose of the end-certificate (by checking
     the extended key usage), use 'gnutls_certificate_verify_peers()' .

     *Returns:* a negative error code on error and 'GNUTLS_E_SUCCESS'
     (0) when the peer's certificate was successfully parsed,
     irrespective of whether it was verified.

     *Since:* 3.1.4

 -- Function: void gnutls_certificate_set_verify_function
          (gnutls_certificate_credentials_t CRED,
          gnutls_certificate_verify_function * FUNC)
     CRED: is a 'gnutls_certificate_credentials_t' structure.

     FUNC: is the callback function

     This function sets a callback to be called when peer's certificate
     has been received in order to verify it on receipt rather than
     doing after the handshake is completed.

     The callback's function prototype is: int
     (*callback)(gnutls_session_t);

     If the callback function is provided then gnutls will call it, in
     the handshake, just after the certificate message has been
     received.  To verify or obtain the certificate the
     'gnutls_certificate_verify_peers2()' ,
     'gnutls_certificate_type_get()' , 'gnutls_certificate_get_peers()'
     functions can be used.

     The callback function should return 0 for the handshake to continue
     or non-zero to terminate.

     *Since:* 2.10.0


File: gnutls.info,  Node: SRP credentials,  Next: PSK credentials,  Prev: Certificate credentials,  Up: Associating the credentials

6.4.2 SRP
---------

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

'INT *note gnutls_srp_allocate_server_credentials:: (gnutls_srp_server_credentials_t * SC)'
'INT *note gnutls_srp_allocate_client_credentials:: (gnutls_srp_client_credentials_t * SC)'
'VOID *note gnutls_srp_free_server_credentials:: (gnutls_srp_server_credentials_t SC)'
'VOID *note gnutls_srp_free_client_credentials:: (gnutls_srp_client_credentials_t SC)'
'INT *note gnutls_srp_set_client_credentials:: (gnutls_srp_client_credentials_t RES, const char * USERNAME, const char * PASSWORD)'

 -- Function: void gnutls_srp_set_client_credentials_function
          (gnutls_srp_client_credentials_t CRED,
          gnutls_srp_client_credentials_function * FUNC)
     CRED: is a 'gnutls_srp_server_credentials_t' structure.

     FUNC: is the callback function

     This function can be used to set a callback to retrieve the
     username and password for client SRP authentication.  The
     callback's function form is:

     int (*callback)(gnutls_session_t, char** username, char**password);

     The 'username' and 'password' must be allocated using
     'gnutls_malloc()' .  'username' and 'password' should be ASCII
     strings or UTF-8 strings prepared using the "SASLprep" profile of
     "stringprep".

     The callback function will be called once per handshake before the
     initial hello message is sent.

     The callback should not return a negative error code the second
     time called, since the handshake procedure will be aborted.

     The callback function should return 0 on success.  -1 indicates an
     error.

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

 -- Function: int gnutls_srp_set_server_credentials_file
          (gnutls_srp_server_credentials_t RES, const char *
          PASSWORD_FILE, const char * PASSWORD_CONF_FILE)
     RES: is a 'gnutls_srp_server_credentials_t' structure.

     PASSWORD_FILE: is the SRP password file (tpasswd)

     PASSWORD_CONF_FILE: is the SRP password conf file (tpasswd.conf)

     This function sets the password files, in a
     'gnutls_srp_server_credentials_t' structure.  Those password files
     hold usernames and verifiers and will be used for SRP
     authentication.

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, or an
     error code.

 -- Function: void gnutls_srp_set_server_credentials_function
          (gnutls_srp_server_credentials_t CRED,
          gnutls_srp_server_credentials_function * FUNC)
     CRED: is a 'gnutls_srp_server_credentials_t' structure.

     FUNC: is the callback function

     This function can be used to set a callback to retrieve the user's
     SRP credentials.  The callback's function form is:

     int (*callback)(gnutls_session_t, const char* username,
     gnutls_datum_t *salt, gnutls_datum_t *verifier, gnutls_datum_t
     *generator, gnutls_datum_t *prime);

     'username' contains the actual username.  The 'salt' , 'verifier' ,
     'generator' and 'prime' must be filled in using the
     'gnutls_malloc()' .  For convenience 'prime' and 'generator' may
     also be one of the static parameters defined in gnutls.h.

     Initially, the data field is NULL in every 'gnutls_datum_t'
     structure that the callback has to fill in.  When the callback is
     done GnuTLS deallocates all of those buffers which are non-NULL,
     regardless of the return value.

     In order to prevent attackers from guessing valid usernames, if a
     user does not exist, g and n values should be filled in using a
     random user's parameters.  In that case the callback must return
     the special value (1).  See 'gnutls_srp_set_server_fake_salt_seed'
     too.  If this is not required for your application, return a
     negative number from the callback to abort the handshake.

     The callback function will only be called once per handshake.  The
     callback function should return 0 on success, while -1 indicates an
     error.


File: gnutls.info,  Node: PSK credentials,  Next: Anonymous credentials,  Prev: SRP credentials,  Up: Associating the credentials

6.4.3 PSK
---------

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

'INT *note gnutls_psk_allocate_server_credentials:: (gnutls_psk_server_credentials_t * SC)'
'INT *note gnutls_psk_allocate_client_credentials:: (gnutls_psk_client_credentials_t * SC)'
'VOID *note gnutls_psk_free_server_credentials:: (gnutls_psk_server_credentials_t SC)'
'VOID *note gnutls_psk_free_client_credentials:: (gnutls_psk_client_credentials_t SC)'

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

'INT *note gnutls_psk_set_client_credentials:: (gnutls_psk_client_credentials_t RES, const char * USERNAME, const gnutls_datum_t * KEY, gnutls_psk_key_flags FLAGS)'

 -- Function: void gnutls_psk_set_client_credentials_function
          (gnutls_psk_client_credentials_t CRED,
          gnutls_psk_client_credentials_function * FUNC)
     CRED: is a 'gnutls_psk_server_credentials_t' structure.

     FUNC: is the callback function

     This function can be used to set a callback to retrieve the
     username and password for client PSK authentication.  The
     callback's function form is: int (*callback)(gnutls_session_t,
     char** username, gnutls_datum_t* key);

     The 'username' and 'key' ->data must be allocated using
     'gnutls_malloc()' .  'username' should be ASCII strings or UTF-8
     strings prepared using the "SASLprep" profile of "stringprep".

     The callback function will be called once per handshake.

     The callback function should return 0 on success.  -1 indicates an
     error.

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

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

 -- Function: int gnutls_psk_set_server_credentials_file
          (gnutls_psk_server_credentials_t RES, const char *
          PASSWORD_FILE)
     RES: is a 'gnutls_psk_server_credentials_t' structure.

     PASSWORD_FILE: is the PSK password file (passwd.psk)

     This function sets the password file, in a
     'gnutls_psk_server_credentials_t' structure.  This password file
     holds usernames and keys and will be used for PSK authentication.

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
     otherwise an error code is returned.

'VOID *note gnutls_psk_set_server_credentials_function:: (gnutls_psk_server_credentials_t CRED, gnutls_psk_server_credentials_function * FUNC)'
'INT *note gnutls_psk_set_server_credentials_hint:: (gnutls_psk_server_credentials_t RES, const char * HINT)'
'CONST CHAR * *note gnutls_psk_client_get_hint:: (gnutls_session_t SESSION)'


File: gnutls.info,  Node: Anonymous credentials,  Prev: PSK credentials,  Up: Associating the credentials

6.4.4 Anonymous
---------------

The key exchange methods for anonymous authentication might require
Diffie-Hellman parameters to be generated by the server and associated
with an anonymous credentials structure.  Check *note Parameter
generation:: for more information.  The initialization functions for the
credentials are shown below.

'INT *note gnutls_anon_allocate_server_credentials:: (gnutls_anon_server_credentials_t * SC)'
'INT *note gnutls_anon_allocate_client_credentials:: (gnutls_anon_client_credentials_t * SC)'
'VOID *note gnutls_anon_free_server_credentials:: (gnutls_anon_server_credentials_t SC)'
'VOID *note gnutls_anon_free_client_credentials:: (gnutls_anon_client_credentials_t SC)'


File: gnutls.info,  Node: Setting up the transport layer,  Next: TLS handshake,  Prev: Associating the credentials,  Up: How to use GnuTLS in applications

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

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

'VOID *note gnutls_transport_set_int:: (gnutls_session_t SESSION, int I)'
'VOID *note gnutls_transport_set_int2:: (gnutls_session_t SESSION, int RECV_INT, int SEND_INT)'

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

'VOID *note gnutls_transport_set_ptr:: (gnutls_session_t SESSION, gnutls_transport_ptr_t PTR)'
'VOID *note gnutls_transport_set_ptr2:: (gnutls_session_t SESSION, gnutls_transport_ptr_t RECV_PTR, gnutls_transport_ptr_t SEND_PTR)'

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

 -- Function: void gnutls_transport_set_push_function (gnutls_session_t
          SESSION, gnutls_push_func PUSH_FUNC)
     SESSION: is a 'gnutls_session_t' structure.

     PUSH_FUNC: a callback function similar to 'write()'

     This is the function where you set a push function for gnutls to
     use in order to send data.  If you are going to use berkeley style
     sockets, you do not need to use this function since the default
     send(2) will probably be ok.  Otherwise you should specify this
     function for gnutls to be able to send data.  The callback should
     return a positive number indicating the bytes sent, and -1 on
     error.

     'push_func' is of the form, ssize_t
     (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);

 -- Function: void gnutls_transport_set_vec_push_function
          (gnutls_session_t SESSION, gnutls_vec_push_func VEC_FUNC)
     SESSION: is a 'gnutls_session_t' structure.

     VEC_FUNC: a callback function similar to 'writev()'

     Using this function you can override the default writev(2) function
     for gnutls to send data.  Setting this callback instead of
     'gnutls_transport_set_push_function()' is recommended since it
     introduces less overhead in the TLS handshake process.

     'vec_func' is of the form, ssize_t (*gnutls_vec_push_func)
     (gnutls_transport_ptr_t, const giovec_t * iov, int iovcnt);

     *Since:* 2.12.0

 -- Function: void gnutls_transport_set_pull_function (gnutls_session_t
          SESSION, gnutls_pull_func PULL_FUNC)
     SESSION: is a 'gnutls_session_t' structure.

     PULL_FUNC: a callback function similar to 'read()'

     This is the function where you set a function for gnutls to receive
     data.  Normally, if you use berkeley style sockets, do not need to
     use this function since the default recv(2) will probably be ok.
     The callback should return 0 on connection termination, a positive
     number indicating the number of bytes received, and -1 on error.

     'gnutls_pull_func' is of the form, ssize_t
     (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);

 -- Function: void gnutls_transport_set_pull_timeout_function
          (gnutls_session_t SESSION, gnutls_pull_timeout_func FUNC)
     SESSION: is a 'gnutls_session_t' structure.

     FUNC: a callback function

     This is the function where you set a function for gnutls to know
     whether data are ready to be received.  It should wait for data a
     given time frame in milliseconds.  The callback should return 0 on
     timeout, a positive number if data can be received, and -1 on
     error.  You'll need to override this function if 'select()' is not
     suitable for the provided transport calls.

     As with 'select()' , if the timeout value is zero the callback
     should return zero if no data are immediately available.

     'gnutls_pull_timeout_func' is of the form, int
     (*gnutls_pull_timeout_func)(gnutls_transport_ptr_t, unsigned int
     ms);

     *Since:* 3.0

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

 -- Function: void gnutls_transport_set_errno (gnutls_session_t SESSION,
          int ERR)
     SESSION: is a 'gnutls_session_t' structure.

     ERR: error value to store in session-specific errno variable.

     Store 'err' in the session-specific errno variable.  Useful values
     for 'err' are EINTR, EAGAIN and EMSGSIZE, other values are treated
     will be treated as real errors in the push/pull function.

     This function is useful in replacement push and pull functions set
     by 'gnutls_transport_set_push_function()' and
     'gnutls_transport_set_pull_function()' under Windows, where the
     replacements may not have access to the same 'errno' variable that
     is used by GnuTLS (e.g., the application is linked to msvcr71.dll
     and gnutls is linked to msvcrt.dll).

GnuTLS currently only interprets the EINTR, EAGAIN and EMSGSIZE errno
values and returns the corresponding GnuTLS error codes:
   * 'GNUTLS_E_INTERRUPTED'
   * 'GNUTLS_E_AGAIN'
   * 'GNUTLS_E_LARGE_PACKET'
The EINTR and EAGAIN values are returned by interrupted system calls, or
when non blocking IO is used.  All GnuTLS functions can be resumed
(called again), if any of the above error codes is returned.  The
EMSGSIZE value is returned when attempting to send a large datagram.

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

 -- Function: void gnutls_transport_set_pull_timeout_function
          (gnutls_session_t SESSION, gnutls_pull_timeout_func FUNC)
     SESSION: is a 'gnutls_session_t' structure.

     FUNC: a callback function

     This is the function where you set a function for gnutls to know
     whether data are ready to be received.  It should wait for data a
     given time frame in milliseconds.  The callback should return 0 on
     timeout, a positive number if data can be received, and -1 on
     error.  You'll need to override this function if 'select()' is not
     suitable for the provided transport calls.

     As with 'select()' , if the timeout value is zero the callback
     should return zero if no data are immediately available.

     'gnutls_pull_timeout_func' is of the form, int
     (*gnutls_pull_timeout_func)(gnutls_transport_ptr_t, unsigned int
     ms);

     *Since:* 3.0

 -- Function: unsigned int gnutls_dtls_get_timeout (gnutls_session_t
          SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     This function will return the milliseconds remaining for a
     retransmission of the previously sent handshake message.  This
     function is useful when DTLS is used in non-blocking mode, to
     estimate when to call 'gnutls_handshake()' if no packets have been
     received.

     *Returns:* the remaining time in milliseconds.

     *Since:* 3.0

* Menu:

* Asynchronous operation::
* DTLS sessions::


File: gnutls.info,  Node: Asynchronous operation,  Next: DTLS sessions,  Up: Setting up the transport layer

6.5.1 Asynchronous operation
----------------------------

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

The 'select' system call can also be used in combination with the GnuTLS
functions.  'select' allows monitoring of sockets and notifies on them
being ready for reading or writing data.  Note however that this system
call cannot notify on data present in GnuTLS read buffers, it is only
applicable to the kernel sockets API. Thus if you are using it for
reading from a GnuTLS session, make sure that any cached data are read
completely.  That can be achieved by checking there are no data waiting
to be read (using *note gnutls_record_check_pending::), either before
the 'select' system call, or after a call to *note gnutls_record_recv::.
GnuTLS does not keep a write buffer, thus when writing no additional
actions are required.

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

 -- Function: int gnutls_record_get_direction (gnutls_session_t SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     This function provides information about the internals of the
     record protocol and is only useful if a prior gnutls function call
     (e.g.  'gnutls_handshake()' ) was interrupted for some reason, that
     is, if a function returned 'GNUTLS_E_INTERRUPTED' or
     'GNUTLS_E_AGAIN' .  In such a case, you might want to call
     'select()' or 'poll()' before calling the interrupted gnutls
     function again.  To tell you whether a file descriptor should be
     selected for either reading or writing,
     'gnutls_record_get_direction()' returns 0 if the interrupted
     function was trying to read data, and 1 if it was trying to write
     data.

     This function's output is unreliable if you are using the 'session'
     in different threads, for sending and receiving.

     *Returns:* 0 if trying to read data, 1 if trying to write data.

Moreover, to prevent blocking from DTLS' retransmission timers to block
a handshake, the *note gnutls_init:: function should be called with the
'GNUTLS_NONBLOCK' flag set (see *note Session initialization::).  In
that case, in order to be able to use the DTLS handshake timers, the
function *note gnutls_dtls_get_timeout:: should be used to estimate when
to call *note gnutls_handshake:: if no packets have been received.


File: gnutls.info,  Node: DTLS sessions,  Prev: Asynchronous operation,  Up: Setting up the transport layer

6.5.2 DTLS sessions
-------------------

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

'INT *note gnutls_key_generate:: (gnutls_datum_t * KEY, unsigned int KEY_SIZE)'
'INT *note gnutls_dtls_cookie_send:: (gnutls_datum_t * KEY, void * CLIENT_DATA, size_t CLIENT_DATA_SIZE, gnutls_dtls_prestate_st * PRESTATE, gnutls_transport_ptr_t PTR, gnutls_push_func PUSH_FUNC)'
'INT *note gnutls_dtls_cookie_verify:: (gnutls_datum_t * KEY, void * CLIENT_DATA, size_t CLIENT_DATA_SIZE, void * _MSG, size_t MSG_SIZE, gnutls_dtls_prestate_st * PRESTATE)'
'VOID *note gnutls_dtls_prestate_set:: (gnutls_session_t SESSION, gnutls_dtls_prestate_st * PRESTATE)'

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

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

'VOID *note gnutls_dtls_set_mtu:: (gnutls_session_t SESSION, unsigned int MTU)'
'UNSIGNED INT *note gnutls_dtls_get_mtu:: (gnutls_session_t SESSION)'
'UNSIGNED INT *note gnutls_dtls_get_data_mtu:: (gnutls_session_t SESSION)'

   ---------- Footnotes ----------

   (1) A key of 128 bits or 16 bytes should be sufficient for this
purpose.


File: gnutls.info,  Node: TLS handshake,  Next: Data transfer and termination,  Prev: Setting up the transport layer,  Up: How to use GnuTLS in applications

6.6 TLS handshake
=================

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

 -- Function: int gnutls_handshake (gnutls_session_t SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     This function does the handshake of the TLS/SSL protocol, and
     initializes the TLS connection.

     This function will fail if any problem is encountered, and will
     return a negative error code.  In case of a client, if the client
     has asked to resume a session, but the server couldn't, then a full
     handshake will be performed.

     The non-fatal errors expected by this function are:
     'GNUTLS_E_INTERRUPTED' , 'GNUTLS_E_AGAIN' ,
     'GNUTLS_E_WARNING_ALERT_RECEIVED' , and
     'GNUTLS_E_GOT_APPLICATION_DATA' , the latter only in a case of
     rehandshake.

     The former two interrupt the handshake procedure due to the lower
     layer being interrupted, and the latter because of an alert that
     may be sent by a server (it is always a good idea to check any
     received alerts).  On these errors call this function again, until
     it returns 0; cf.  'gnutls_record_get_direction()' and
     'gnutls_error_is_fatal()' .  In DTLS sessions the non-fatal error
     'GNUTLS_E_LARGE_PACKET' is also possible, and indicates that the
     MTU should be adjusted.

     If this function is called by a server after a rehandshake request
     then 'GNUTLS_E_GOT_APPLICATION_DATA' or
     'GNUTLS_E_WARNING_ALERT_RECEIVED' may be returned.  Note that these
     are non fatal errors, only in the specific case of a rehandshake.
     Their meaning is that the client rejected the rehandshake request
     or in the case of 'GNUTLS_E_GOT_APPLICATION_DATA' it could also
     mean that some data were pending.

     *Returns:* 'GNUTLS_E_SUCCESS' on success, otherwise a negative
     error code.

 -- Function: void gnutls_handshake_set_timeout (gnutls_session_t
          SESSION, unsigned int MS)
     SESSION: is a 'gnutls_session_t' structure.

     MS: is a timeout value in milliseconds

     This function sets the timeout for the handshake process to the
     provided value.  Use an 'ms' value of zero to disable timeout, or
     'GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT' for a reasonable default value.

     *Since:* 3.1.0

The handshake process doesn't ensure the verification of the peer's
identity.  When certificates are in use, this can be done, either after
the handshake is complete, or during the handshake if *note
gnutls_certificate_set_verify_function:: has been used.  In both cases
the *note gnutls_certificate_verify_peers2:: function can be used to
verify the peer's certificate (see *note Certificate authentication::
for more information).

'INT *note gnutls_certificate_verify_peers2:: (gnutls_session_t SESSION, unsigned int * STATUS)'


File: gnutls.info,  Node: Data transfer and termination,  Next: Buffered data transfer,  Prev: TLS handshake,  Up: How to use GnuTLS in applications

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

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

 -- Function: ssize_t gnutls_record_send (gnutls_session_t SESSION,
          const void * DATA, size_t DATA_SIZE)
     SESSION: is a 'gnutls_session_t' structure.

     DATA: contains the data to send

     DATA_SIZE: is the length of the data

     This function has the similar semantics with 'send()' .  The only
     difference is that it accepts a GnuTLS session, and uses different
     error codes.  Note that if the send buffer is full, 'send()' will
     block this function.  See the 'send()' documentation for more
     information.

     You can replace the default push function which is 'send()' , by
     using 'gnutls_transport_set_push_function()' .

     If the EINTR is returned by the internal push function then
     'GNUTLS_E_INTERRUPTED' will be returned.  If 'GNUTLS_E_INTERRUPTED'
     or 'GNUTLS_E_AGAIN' is returned, you must call this function again,
     with the exact same parameters; alternatively you could provide a
     'NULL' pointer for data, and 0 for size.  cf.
     'gnutls_record_get_direction()' .

     Note that in DTLS this function will return the
     'GNUTLS_E_LARGE_PACKET' error code if the send data exceed the data
     MTU value - as returned by 'gnutls_dtls_get_data_mtu()' .  The
     errno value EMSGSIZE also maps to 'GNUTLS_E_LARGE_PACKET' .  Note
     that since 3.2.13 this function can be called under cork in DTLS
     mode, and will refuse to send data over the MTU size by returning
     'GNUTLS_E_LARGE_PACKET' .

     *Returns:* The number of bytes sent, or a negative error code.  The
     number of bytes sent might be less than 'data_size' .  The maximum
     number of bytes this function can send in a single call depends on
     the negotiated maximum record size.

 -- Function: ssize_t gnutls_record_recv (gnutls_session_t SESSION, void
          * DATA, size_t DATA_SIZE)
     SESSION: is a 'gnutls_session_t' structure.

     DATA: the buffer that the data will be read into

     DATA_SIZE: the number of requested bytes

     This function has the similar semantics with 'recv()' .  The only
     difference is that it accepts a GnuTLS session, and uses different
     error codes.  In the special case that a server requests a
     renegotiation, the client may receive an error code of
     'GNUTLS_E_REHANDSHAKE' .  This message may be simply ignored,
     replied with an alert 'GNUTLS_A_NO_RENEGOTIATION' , or replied with
     a new handshake, depending on the client's will.  If 'EINTR' is
     returned by the internal push function (the default is 'recv()' )
     then 'GNUTLS_E_INTERRUPTED' will be returned.  If
     'GNUTLS_E_INTERRUPTED' or 'GNUTLS_E_AGAIN' is returned, you must
     call this function again to get the data.  See also
     'gnutls_record_get_direction()' .  A server may also receive
     'GNUTLS_E_REHANDSHAKE' when a client has initiated a handshake.  In
     that case the server can only initiate a handshake or terminate the
     connection.

     *Returns:* The number of bytes received and zero on EOF (for stream
     connections).  A negative error code is returned in case of an
     error.  The number of bytes received might be less than the
     requested 'data_size' .

 -- Function: int gnutls_error_is_fatal (int ERROR)
     ERROR: is a GnuTLS error code, a negative error code

     If a GnuTLS function returns a negative error code you may feed
     that value to this function to see if the error condition is fatal
     to a TLS session (i.e., must be terminated).

     Note that you may also want to check the error code manually, since
     some non-fatal errors to the protocol (such as a warning alert or a
     rehandshake request) may be fatal for your program.

     This function is only useful if you are dealing with errors from
     functions that relate to a TLS session (e.g., record layer or
     handshake layer handling functions).

     *Returns:* Non-zero value on fatal errors or zero on non-fatal.

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

 -- Function: ssize_t gnutls_record_recv_seq (gnutls_session_t SESSION,
          void * DATA, size_t DATA_SIZE, unsigned char * SEQ)
     SESSION: is a 'gnutls_session_t' structure.

     DATA: the buffer that the data will be read into

     DATA_SIZE: the number of requested bytes

     SEQ: is the packet's 64-bit sequence number.  Should have space for
     8 bytes.

     This function is the same as 'gnutls_record_recv()' , except that
     it returns in addition to data, the sequence number of the data.
     This is useful in DTLS where record packets might be received
     out-of-order.  The returned 8-byte sequence number is an integer in
     big-endian format and should be treated as a unique message
     identification.

     *Returns:* The number of bytes received and zero on EOF. A negative
     error code is returned in case of an error.  The number of bytes
     received might be less than 'data_size' .

     *Since:* 3.0

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

 -- Function: size_t gnutls_record_check_pending (gnutls_session_t
          SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     This function checks if there are unread data in the gnutls
     buffers.  If the return value is non-zero the next call to
     'gnutls_record_recv()' is guaranteed not to block.

     *Returns:* Returns the size of the data or zero.
'INT *note gnutls_record_get_direction:: (gnutls_session_t SESSION)'

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

 -- Function: int gnutls_bye (gnutls_session_t SESSION,
          gnutls_close_request_t HOW)
     SESSION: is a 'gnutls_session_t' structure.

     HOW: is an integer

     Terminates the current TLS/SSL connection.  The connection should
     have been initiated using 'gnutls_handshake()' .  'how' should be
     one of 'GNUTLS_SHUT_RDWR' , 'GNUTLS_SHUT_WR' .

     In case of 'GNUTLS_SHUT_RDWR' the TLS session gets terminated and
     further receives and sends will be disallowed.  If the return value
     is zero you may continue using the underlying transport layer.
     'GNUTLS_SHUT_RDWR' sends an alert containing a close request and
     waits for the peer to reply with the same message.

     In case of 'GNUTLS_SHUT_WR' the TLS session gets terminated and
     further sends will be disallowed.  In order to reuse the connection
     you should wait for an EOF from the peer.  'GNUTLS_SHUT_WR' sends
     an alert containing a close request.

     Note that not all implementations will properly terminate a TLS
     connection.  Some of them, usually for performance reasons, will
     terminate only the underlying transport layer, and thus not
     distinguishing between a malicious party prematurely terminating
     the connection and normal termination.

     This function may also return 'GNUTLS_E_AGAIN' or
     'GNUTLS_E_INTERRUPTED' ; cf.  'gnutls_record_get_direction()' .

     *Returns:* 'GNUTLS_E_SUCCESS' on success, or an error code, see
     function documentation for entire semantics.

 -- Function: void gnutls_deinit (gnutls_session_t SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     This function clears all buffers associated with the 'session' .
     This function will also remove session data from the session
     database if the session was terminated abnormally.


File: gnutls.info,  Node: Buffered data transfer,  Next: Handling alerts,  Prev: Data transfer and termination,  Up: How to use GnuTLS in applications

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

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

 -- Function: void gnutls_record_cork (gnutls_session_t SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     If called, 'gnutls_record_send()' will no longer send any records.
     Any sent records will be cached until 'gnutls_record_uncork()' is
     called.

     This function is safe to use with DTLS after GnuTLS 3.3.0.

     *Since:* 3.1.9

 -- Function: int gnutls_record_uncork (gnutls_session_t SESSION,
          unsigned int FLAGS)
     SESSION: is a 'gnutls_session_t' structure.

     FLAGS: Could be zero or 'GNUTLS_RECORD_WAIT'

     This resets the effect of 'gnutls_record_cork()' , and flushes any
     pending data.  If the 'GNUTLS_RECORD_WAIT' flag is specified then
     this function will block until the data is sent or a fatal error
     occurs (i.e., the function will retry on 'GNUTLS_E_AGAIN' and
     'GNUTLS_E_INTERRUPTED' ).

     If the flag 'GNUTLS_RECORD_WAIT' is not specified and the function
     is interrupted then the 'GNUTLS_E_AGAIN' or 'GNUTLS_E_INTERRUPTED'
     errors will be returned.  To obtain the data left in the corked
     buffer use 'gnutls_record_check_corked()' .

     *Returns:* On success the number of transmitted data is returned,
     or otherwise a negative error code.

     *Since:* 3.1.9


File: gnutls.info,  Node: Handling alerts,  Next: Priority Strings,  Prev: Buffered data transfer,  Up: How to use GnuTLS in applications

6.9 Handling alerts
===================

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

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

 -- Function: gnutls_alert_description_t gnutls_alert_get
          (gnutls_session_t SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     This function will return the last alert number received.  This
     function should be called when 'GNUTLS_E_WARNING_ALERT_RECEIVED' or
     'GNUTLS_E_FATAL_ALERT_RECEIVED' errors are returned by a gnutls
     function.  The peer may send alerts if he encounters an error.  If
     no alert has been received the returned value is undefined.

     *Returns:* the last alert received, a 'gnutls_alert_description_t'
     value.

 -- Function: const char * gnutls_alert_get_name
          (gnutls_alert_description_t ALERT)
     ALERT: is an alert number.

     This function will return a string that describes the given alert
     number, or 'NULL' .  See 'gnutls_alert_get()' .

     *Returns:* string corresponding to 'gnutls_alert_description_t'
     value.

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

 -- Function: int gnutls_alert_send (gnutls_session_t SESSION,
          gnutls_alert_level_t LEVEL, gnutls_alert_description_t DESC)
     SESSION: is a 'gnutls_session_t' structure.

     LEVEL: is the level of the alert

     DESC: is the alert description

     This function will send an alert to the peer in order to inform him
     of something important (eg.  his Certificate could not be
     verified).  If the alert level is Fatal then the peer is expected
     to close the connection, otherwise he may ignore the alert and
     continue.

     The error code of the underlying record send function will be
     returned, so you may also receive 'GNUTLS_E_INTERRUPTED' or
     'GNUTLS_E_AGAIN' as well.

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
     otherwise an error code is returned.

 -- Function: int gnutls_error_to_alert (int ERR, int * LEVEL)
     ERR: is a negative integer

     LEVEL: the alert level will be stored there

     Get an alert depending on the error code returned by a gnutls
     function.  All alerts sent by this function should be considered
     fatal.  The only exception is when 'err' is 'GNUTLS_E_REHANDSHAKE'
     , where a warning alert should be sent to the peer indicating that
     no renegotiation will be performed.

     If there is no mapping to a valid alert the alert to indicate
     internal error is returned.

     *Returns:* the alert code to use for a particular error code.


File: gnutls.info,  Node: Priority Strings,  Next: Selecting cryptographic key sizes,  Prev: Handling alerts,  Up: How to use GnuTLS in applications

6.10 Priority strings
=====================

The GnuTLS priority strings specify the TLS session's handshake
algorithms and options in a compact, easy-to-use format.  That string
may contain a single initial keyword such as in *note Table 6.3:
tab:prio-keywords. and may be followed by additional algorithm or
special keywords.  Note that their description is intentionally avoiding
specific algorithm details, as the priority strings are not constant
between gnutls versions (they are periodically updated to account for
cryptographic advances while providing compatibility with old clients
and servers).

'INT *note gnutls_priority_set_direct:: (gnutls_session_t SESSION, const char * PRIORITIES, const char ** ERR_POS)'
'INT *note gnutls_priority_set:: (gnutls_session_t SESSION, gnutls_priority_t PRIORITY)'

Keyword        Description
------------------------------------------------------------------
@KEYWORD       Means that a compile-time specified system
               configuration file(1) will be used to expand the
               provided keyword.  That is used to impose
               system-specific policies.  It may be followed by
               additional options that will be appended to the
               system string (e.g., "@SYSTEM:+SRP"). The system
               file should have the format 'KEYWORD=VALUE',
               e.g., 'SYSTEM=NORMAL:-ARCFOUR-128'.
               
PERFORMANCE    All the known to be secure ciphersuites are
               enabled, limited to 128 bit ciphers and sorted
               by terms of speed performance.  The message
               authenticity security level is of 64 bits or
               more, and the certificate verification profile
               is set to GNUTLS_PROFILE_LOW (80-bits).
               
NORMAL         Means all the known to be secure ciphersuites.
               The ciphers are sorted by security margin,
               although the 256-bit ciphers are included as a
               fallback only.  The message authenticity
               security level is of 64 bits or more, and the
               certificate verification profile is set to
               GNUTLS_PROFILE_LOW (80-bits).
               
               This priority string implicitly enables ECDHE
               and DHE. The ECDHE ciphersuites are placed first
               in the priority order, but due to compatibility
               issues with the DHE ciphersuites they are placed
               last in the priority order, after the plain RSA
               ciphersuites.
               
LEGACY         This sets the NORMAL settings that were used for
               GnuTLS 3.2.x or earlier.  There is no
               verification profile set, and the allowed DH
               primes are considered weak today (but are often
               used by misconfigured servers).
               
PFS            Means all the known to be secure ciphersuites
               that support perfect forward secrecy (ECDHE and
               DHE). The ciphers are sorted by security margin,
               although the 256-bit ciphers are included as a
               fallback only.  The message authenticity
               security level is of 80 bits or more, and the
               certificate verification profile is set to
               GNUTLS_PROFILE_LOW (80-bits).  This option is
               available since 3.2.4 or later.
               
SECURE128      Means all known to be secure ciphersuites that
               offer a security level 128-bit or more.  The
               message authenticity security level is of 80
               bits or more, and the certificate verification
               profile is set to GNUTLS_PROFILE_LOW (80-bits).
               
SECURE192      Means all the known to be secure ciphersuites
               that offer a security level 192-bit or more.
               The message authenticity security level is of
               128 bits or more, and the certificate
               verification profile is set to
               GNUTLS_PROFILE_HIGH (128-bits).
               
SECURE256      Currently alias for SECURE192.  This option,
               will enable ciphers which use a 256-bit key but,
               due to limitations of the TLS protocol, the
               overall security level will be 192-bits (the
               security level depends on more factors than
               cipher key size).
               
SUITEB128      Means all the NSA Suite B cryptography (RFC5430)
               ciphersuites with an 128 bit security level, as
               well as the enabling of the corresponding
               verification profile.
               
SUITEB192      Means all the NSA Suite B cryptography (RFC5430)
               ciphersuites with an 192 bit security level, as
               well as the enabling of the corresponding
               verification profile.
               
EXPORT         This priority string should be treated as
               deprecated.  GnuTLS no longer negotiates 40-bit
               ciphers.
               
NONE           Means nothing is enabled.  This disables even
               protocols and compression methods.  It should be
               followed by the algorithms to be enabled.
               

Table 6.3: Supported initial keywords.

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

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

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

The order with which every algorithm or protocol is specified is
significant.  Algorithms specified before others will take precedence.
The supported algorithms and protocols are shown in *note Table 6.4:
tab:prio-algorithms.  To avoid collisions in order to specify a
compression algorithm in the priority string you have to prefix it with
"COMP-", protocol versions with "VERS-", signature algorithms with
"SIGN-" and certificate types with "CTYPE-".  All other algorithms don't
need a prefix.  Each specified keyword can be prefixed with any of the
following characters.

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

Type           Keywords
------------------------------------------------------------------
Ciphers        AES-128-CBC, AES-256-CBC, AES-128-GCM,
               CAMELLIA-128-CBC, CAMELLIA-256-CBC, ARCFOUR-128,
               3DES-CBC ARCFOUR-40.  Catch all name is
               CIPHER-ALL which will add all the algorithms
               from NORMAL priority.
               
Key exchange   RSA, DHE-RSA, DHE-DSS, SRP, SRP-RSA, SRP-DSS,
               PSK, DHE-PSK, ECDHE-RSA, ANON-ECDH, ANON-DH. The
               Catch all name is KX-ALL which will add all the
               algorithms from NORMAL priority.
               
               Add '!DHE-RSA:!DHE-DSS' to the priority string
               to disable DHE.
               
MAC            MD5, SHA1, SHA256, SHA384, AEAD (used with GCM
               ciphers only).  All algorithms from NORMAL
               priority can be accessed with MAC-ALL.
               
Compression    COMP-NULL, COMP-DEFLATE. Catch all is COMP-ALL.
algorithms     
TLS versions   VERS-SSL3.0, VERS-TLS1.0, VERS-TLS1.1,
               VERS-TLS1.2, VERS-DTLS1.2, VERS-DTLS1.0.  Catch
               all is VERS-TLS-ALL and VERS-DTLS-ALL.
               
Signature      SIGN-RSA-SHA1, SIGN-RSA-SHA224, SIGN-RSA-SHA256,
algorithms     SIGN-RSA-SHA384, SIGN-RSA-SHA512, SIGN-DSA-SHA1,
               SIGN-DSA-SHA224, SIGN-DSA-SHA256, SIGN-RSA-MD5.
               Catch all is SIGN-ALL. This is only valid for
               TLS 1.2 and later.
               
Elliptic       CURVE-SECP192R1, CURVE-SECP224R1,
curves         CURVE-SECP256R1, CURVE-SECP384R1,
               CURVE-SECP521R1.  Catch all is CURVE-ALL.
               

Table 6.4: The supported algorithm keywords in priority strings.

Note that the DHE key exchange methods are generally slower(2) than
their elliptic curves counterpart (ECDHE). Moreover the plain
Diffie-Hellman key exchange requires parameters to be generated and
associated with a credentials structure by the server (see *note
Parameter generation::).

The available special keywords are shown in *note Table 6.5:
tab:prio-special1. and *note Table 6.6: tab:prio-special2.

Keyword                          Description
                                 
------------------------------------------------------------------
%COMPAT                          will enable compatibility
                                 mode.  It might mean that
                                 violations of the protocols
                                 are allowed as long as maximum
                                 compatibility with problematic
                                 clients and servers is
                                 achieved.  More specifically
                                 this string would disable TLS
                                 record random padding,
                                 tolerate packets over the
                                 maximum allowed TLS record,
                                 and add a padding to TLS
                                 Client Hello packet to prevent
                                 it being in the 256-512 range
                                 which is known to be causing
                                 issues with a commonly used
                                 firewall.
                                 
%DUMBFW                          will add a private extension
                                 with bogus data that make the
                                 client hello exceed 512 bytes.
                                 This avoids a black hole
                                 behavior in some firewalls.
                                 This is a non-standard TLS
                                 extension, use with care.
                                 
%NO_EXTENSIONS                   will prevent the sending of
                                 any TLS extensions in client
                                 side.  Note that TLS 1.2
                                 requires extensions to be
                                 used, as well as safe
                                 renegotiation thus this option
                                 must be used with care.
                                 
%SERVER_PRECEDENCE               The ciphersuite will be
                                 selected according to server
                                 priorities and not the
                                 client's.
                                 
%SSL3_RECORD_VERSION             will use SSL3.0 record version
                                 in client hello.  This is the
                                 default.
                                 
%LATEST_RECORD_VERSION           will use the latest TLS
                                 version record version in
                                 client hello.
                                 

Table 6.5: Special priority string keywords.

Keyword                          Description
                                 
------------------------------------------------------------------
%STATELESS_COMPRESSION           will disable keeping state
                                 across records when
                                 compressing.  This may help to
                                 mitigate attacks when
                                 compression is used but an
                                 attacker is in control of
                                 input data.  This has to be
                                 used only when the data that
                                 are possibly controlled by an
                                 attacker are placed in
                                 separate records.
                                 
%DISABLE_WILDCARDS               will disable matching
                                 wildcards when comparing
                                 hostnames in certificates.
                                 
%DISABLE_SAFE_RENEGOTIATION      will completely disable safe
                                 renegotiation completely.  Do
                                 not use unless you know what
                                 you are doing.
                                 
%UNSAFE_RENEGOTIATION            will allow handshakes and
                                 re-handshakes without the safe
                                 renegotiation extension.  Note
                                 that for clients this mode is
                                 insecure (you may be under
                                 attack), and for servers it
                                 will allow insecure clients to
                                 connect (which could be fooled
                                 by an attacker).  Do not use
                                 unless you know what you are
                                 doing and want maximum
                                 compatibility.
                                 
%PARTIAL_RENEGOTIATION           will allow initial handshakes
                                 to proceed, but not
                                 re-handshakes.  This leaves
                                 the client vulnerable to
                                 attack, and servers will be
                                 compatible with non-upgraded
                                 clients for initial
                                 handshakes.  This is currently
                                 the default for clients and
                                 servers, for compatibility
                                 reasons.
                                 
%SAFE_RENEGOTIATION              will enforce safe
                                 renegotiation.  Clients and
                                 servers will refuse to talk to
                                 an insecure peer.  Currently
                                 this causes interoperability
                                 problems, but is required for
                                 full protection.
                                 
%VERIFY_ALLOW_SIGN_RSA_MD5       will allow RSA-MD5 signatures
                                 in certificate chains.
                                 
%VERIFY_DISABLE_CRL_CHECKS       will disable CRL or OCSP
                                 checks in the verification of
                                 the certificate chain.
                                 
%VERIFY_ALLOW_X509_V1_CA_CRT     will allow V1 CAs in chains.
                                 
%PROFILE_(LOW|LEGACY|MEDIUM|HIGH|ULTRA)require a certificate
                                 verification profile the
                                 corresponds to the specified
                                 security level, see
                                 *note Table 6.7: tab:key-sizes.
                                 for the mappings to values.
                                 
%PROFILE_(SUITEB128|SUITEB192)   require a certificate
                                 verification profile the
                                 corresponds to SUITEB. Note
                                 that an initial keyword that
                                 enables SUITEB automatically
                                 sets the profile.
                                 

Table 6.6: More priority string keywords.

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

Example priority strings are:
     The system imposed security level:
         "SYSTEM"

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

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

     Specifying the defaults except ARCFOUR-128:
         "NORMAL:-ARCFOUR-128"

     Enabling the 128-bit secure ciphers, while disabling SSL 3.0 and enabling compression:
         "SECURE128:-VERS-SSL3.0:+COMP-DEFLATE"

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

   ---------- Footnotes ----------

   (1) The default is '/etc/gnutls/default-priorities'.

   (2) It depends on the group used.  Primes with lesser bits are always
faster, but also easier to break.  See *note Selecting cryptographic key
sizes:: for the acceptable security levels.


File: gnutls.info,  Node: Selecting cryptographic key sizes,  Next: Advanced topics,  Prev: Priority Strings,  Up: How to use GnuTLS in applications

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

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

SecurityRSA, DH   ECC     Security       Description
bits    and SRP   key     parameter      
        parameter size
        size
-----------------------------------------------------------------
<64     <768      <128    'INSECURE'     Considered to be
                                         insecure
                                         
64      768       128     'VERY WEAK'    Short term protection
                                         against individuals
                                         
72      1008      160     'WEAK'         Short term protection
                                         against small
                                         organizations
                                         
80      1024      160     'LOW'          Very short term
                                         protection against
                                         agencies (corresponds
                                         to ENISA legacy
                                         level)
                                         
96      1776      192     'LEGACY'       Legacy standard level
                                         
112     2048      224     'MEDIUM'       Medium-term
                                         protection
                                         
128     3072      256     'HIGH'         Long term protection
                                         
256     15424     512     'ULTRA'        Foreseeable future
                                         

Table 6.7: Key sizes and security parameters.

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

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

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

 -- Function: unsigned int gnutls_sec_param_to_pk_bits
          (gnutls_pk_algorithm_t ALGO, gnutls_sec_param_t PARAM)
     ALGO: is a public key algorithm

     PARAM: is a security parameter

     When generating private and public key pairs a difficult question
     is which size of "bits" the modulus will be in RSA and the group
     size in DSA. The easy answer is 1024, which is also wrong.  This
     function will convert a human understandable security parameter to
     an appropriate size for the specific algorithm.

     *Returns:* The number of bits, or (0).

     *Since:* 2.12.0

 -- Function: gnutls_sec_param_t gnutls_pk_bits_to_sec_param
          (gnutls_pk_algorithm_t ALGO, unsigned int BITS)
     ALGO: is a public key algorithm

     BITS: is the number of bits

     This is the inverse of 'gnutls_sec_param_to_pk_bits()' .  Given an
     algorithm and the number of bits, it will return the security
     parameter.  This is a rough indication.

     *Returns:* The security parameter.

     *Since:* 2.12.0

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

'CONST CHAR * *note gnutls_sec_param_get_name:: (gnutls_sec_param_t PARAM)'

The following functions will set the minimum acceptable group size for
Diffie-Hellman and SRP authentication.
'VOID *note gnutls_dh_set_prime_bits:: (gnutls_session_t SESSION, unsigned int BITS)'
'VOID *note gnutls_srp_set_prime_bits:: (gnutls_session_t SESSION, unsigned int BITS)'


File: gnutls.info,  Node: Advanced topics,  Prev: Selecting cryptographic key sizes,  Up: How to use GnuTLS in applications

6.12 Advanced topics
====================

* Menu:

* Session resumption::
* Certificate verification::
* Parameter generation::
* Deriving keys for other applications/protocols::
* Channel Bindings::
* Interoperability::
* Compatibility with the OpenSSL library::


File: gnutls.info,  Node: Session resumption,  Next: Certificate verification,  Up: Advanced topics

6.12.1 Session resumption
-------------------------

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

To reduce time and roundtrips spent in a handshake the client can
request session resumption from a server that previously shared a
session with the client.  For that the client has to retrieve and store
the session parameters.  Before establishing a new session to the same
server the parameters must be re-associated with the GnuTLS session
using *note gnutls_session_set_data::.

'INT *note gnutls_session_get_data2:: (gnutls_session_t SESSION, gnutls_datum_t * DATA)'
'INT *note gnutls_session_get_id2:: (gnutls_session_t SESSION, gnutls_datum_t * SESSION_ID)'
'INT *note gnutls_session_set_data:: (gnutls_session_t SESSION, const void * SESSION_DATA, size_t SESSION_DATA_SIZE)'

Keep in mind that sessions will be expired after some time, depending on
the server, and a server may choose not to resume a session even when
requested to.  The expiration is to prevent temporal session keys from
becoming long-term keys.  Also note that as a client you must enable,
using the priority functions, at least the algorithms used in the last
session.

 -- Function: int gnutls_session_is_resumed (gnutls_session_t SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     Check whether session is resumed or not.

     *Returns:* non zero if this session is resumed, or a zero if this
     is a new session.

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

In order to support resumption a server can store the session security
parameters in a local database or by using session tickets (see *note
Session tickets::) to delegate storage to the client.  Because session
tickets might not be supported by all clients, servers could combine the
two methods.

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

'VOID *note gnutls_db_set_retrieve_function:: (gnutls_session_t SESSION, gnutls_db_retr_func RETR_FUNC)'
'VOID *note gnutls_db_set_store_function:: (gnutls_session_t SESSION, gnutls_db_store_func STORE_FUNC)'
'VOID *note gnutls_db_set_ptr:: (gnutls_session_t SESSION, void * PTR)'
'VOID *note gnutls_db_set_remove_function:: (gnutls_session_t SESSION, gnutls_db_remove_func REM_FUNC)'
'INT *note gnutls_db_check_entry:: (gnutls_session_t SESSION, gnutls_datum_t SESSION_ENTRY)'

A server utilizing tickets should generate ticket encryption and
authentication keys using *note gnutls_session_ticket_key_generate::.
Those keys should be associated with the GnuTLS session using *note
gnutls_session_ticket_enable_server::, and should be rotated regularly
(e.g., every few hours), to prevent them from becoming long-term keys
which if revealed could be used to decrypt all previous sessions.

 -- Function: int gnutls_session_ticket_enable_server (gnutls_session_t
          SESSION, const gnutls_datum_t * KEY)
     SESSION: is a 'gnutls_session_t' structure.

     KEY: key to encrypt session parameters.

     Request that the server should attempt session resumption using
     SessionTicket.  'key' must be initialized with
     'gnutls_session_ticket_key_generate()' .

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, or an
     error code.

     *Since:* 2.10.0

 -- Function: int gnutls_session_ticket_key_generate (gnutls_datum_t *
          KEY)
     KEY: is a pointer to a 'gnutls_datum_t' which will contain a newly
     created key.

     Generate a random key to encrypt security parameters within
     SessionTicket.

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, or an
     error code.

     *Since:* 2.10.0

 -- Function: int gnutls_session_resumption_requested (gnutls_session_t
          SESSION)
     SESSION: is a 'gnutls_session_t' structure.

     Check whether the client has asked for session resumption.  This
     function is valid only on server side.

     *Returns:* non zero if session resumption was asked, or a zero if
     not.

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


File: gnutls.info,  Node: Certificate verification,  Next: Parameter generation,  Prev: Session resumption,  Up: Advanced topics

6.12.2 Certificate verification
-------------------------------

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

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

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

 -- Function: int gnutls_verify_stored_pubkey (const char * DB_NAME,
          gnutls_tdb_t TDB, const char * HOST, const char * SERVICE,
          gnutls_certificate_type_t CERT_TYPE, const gnutls_datum_t *
          CERT, unsigned int FLAGS)
     DB_NAME: A file specifying the stored keys (use NULL for the
     default)

     TDB: A storage structure or NULL to use the default

     HOST: The peer's name

     SERVICE: non-NULL if this key is specific to a service (e.g.  http)

     CERT_TYPE: The type of the certificate

     CERT: The raw (der) data of the certificate

     FLAGS: should be 0.

     This function will try to verify the provided (raw or DER-encoded)
     certificate using a list of stored public keys.  The 'service'
     field if non-NULL should be a port number.

     The 'retrieve' variable if non-null specifies a custom backend for
     the retrieval of entries.  If it is NULL then the default file
     backend will be used.  In POSIX-like systems the file backend uses
     the $HOME/.gnutls/known_hosts file.

     Note that if the custom storage backend is provided the retrieval
     function should return 'GNUTLS_E_CERTIFICATE_KEY_MISMATCH' if the
     host/service pair is found but key doesn't match,
     'GNUTLS_E_NO_CERTIFICATE_FOUND' if no such host/service with the
     given key is found, and 0 if it was found.  The storage function
     should return 0 on success.

     *Returns:* If no associated public key is found then
     'GNUTLS_E_NO_CERTIFICATE_FOUND' will be returned.  If a key is
     found but does not match 'GNUTLS_E_CERTIFICATE_KEY_MISMATCH' is
     returned.  On success, 'GNUTLS_E_SUCCESS' (0) is returned, or a
     negative error value on other errors.

     *Since:* 3.0.13

 -- Function: int gnutls_store_pubkey (const char * DB_NAME,
          gnutls_tdb_t TDB, const char * HOST, const char * SERVICE,
          gnutls_certificate_type_t CERT_TYPE, const gnutls_datum_t *
          CERT, time_t EXPIRATION, unsigned int FLAGS)
     DB_NAME: A file specifying the stored keys (use NULL for the
     default)

     TDB: A storage structure or NULL to use the default

     HOST: The peer's name

     SERVICE: non-NULL if this key is specific to a service (e.g.  http)

     CERT_TYPE: The type of the certificate

     CERT: The data of the certificate

     EXPIRATION: The expiration time (use 0 to disable expiration)

     FLAGS: should be 0.

     This function will store the provided (raw or DER-encoded)
     certificate to the list of stored public keys.  The key will be
     considered valid until the provided expiration time.

     The 'store' variable if non-null specifies a custom backend for the
     storage of entries.  If it is NULL then the default file backend
     will be used.

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
     otherwise a negative error value.

     *Since:* 3.0.13

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

 -- Function: int gnutls_store_commitment (const char * DB_NAME,
          gnutls_tdb_t TDB, const char * HOST, const char * SERVICE,
          gnutls_digest_algorithm_t HASH_ALGO, const gnutls_datum_t *
          HASH, time_t EXPIRATION, unsigned int FLAGS)
     DB_NAME: A file specifying the stored keys (use NULL for the
     default)

     TDB: A storage structure or NULL to use the default

     HOST: The peer's name

     SERVICE: non-NULL if this key is specific to a service (e.g.  http)

     HASH_ALGO: The hash algorithm type

     HASH: The raw hash

     EXPIRATION: The expiration time (use 0 to disable expiration)

     FLAGS: should be 0.

     This function will store the provided hash commitment to the list
     of stored public keys.  The key with the given hash will be
     considered valid until the provided expiration time.

     The 'store' variable if non-null specifies a custom backend for the
     storage of entries.  If it is NULL then the default file backend
     will be used.

     Note that this function is not thread safe with the default
     backend.

     *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
     otherwise a negative error value.

     *Since:* 3.0

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

'INT *note gnutls_tdb_init:: (gnutls_tdb_t * TDB)'
'VOID *note gnutls_tdb_deinit:: (gnutls_tdb_t TDB)'
'VOID *note gnutls_tdb_set_verify_func:: (gnutls_tdb_t TDB, gnutls_tdb_verify_func VERIFY)'
'VOID *note gnutls_tdb_set_store_func:: (gnutls_tdb_t TDB, gnutls_tdb_store_func STORE)'
'VOID *note gnutls_tdb_set_store_commitment_func:: (gnutls_tdb_t TDB, gnutls_tdb_store_commitment_func CSTORE)'

6.12.2.2 DANE verification
..........................

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

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

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

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

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

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

 -- Function: int dane_verify_crt (dane_state_t S, const gnutls_datum_t
          * CHAIN, unsigned CHAIN_SIZE, gnutls_certificate_type_t
          CHAIN_TYPE, const char * HOSTNAME, const char * PROTO,
          unsigned int PORT, unsigned int SFLAGS, unsigned int VFLAGS,
          unsigned int * VERIFY)
     S: A DANE state structure (may be NULL)

     CHAIN: A certificate chain

     CHAIN_SIZE: The size of the chain

     CHAIN_TYPE: The type of the certificate chain

     HOSTNAME: The hostname associated with the chain

     PROTO: The protocol of the service connecting (e.g.  tcp)

     PORT: The port of the service connecting (e.g.  443)

     SFLAGS: Flags for the the initialization of 's' (if NULL)

     VFLAGS: Verification flags; an OR'ed list of 'dane_verify_flags_t'
     .

     VERIFY: An OR'ed list of 'dane_verify_status_t' .

     This function will verify the given certificate chain against the
     CA constrains and/or the certificate available via DANE. If no
     information via DANE can be obtained the flag
     'DANE_VERIFY_NO_DANE_INFO' is set.  If a DNSSEC signature is not
     available for the DANE record then the verify flag
     'DANE_VERIFY_NO_DNSSEC_DATA' is set.

     Due to the many possible options of DANE, there is no single threat
     model countered.  When notifying the user about DANE verification
     results it may be better to mention: DANE verification did not
     reject the certificate, rather than mentioning a successful DANE
     verication.

     Note that this function is designed to be run in addition to PKIX -
     certificate chain - verification.  To be run independently the
     'DANE_VFLAG_ONLY_CHECK_EE_USAGE' flag should be specified; then the
     function will check whether the key of the peer matches the key
     advertized in the DANE entry.

     *Returns:* a negative error code on error and 'DANE_E_SUCCESS' (0)
     when the DANE entries were successfully parsed, irrespective of
     whether they were verified (see 'verify' for that information).  If
     no usable entries were encountered
     'DANE_E_REQUESTED_DATA_NOT_AVAILABLE' will be returned.

'INT *note dane_verify_session_crt:: (dane_state_t S, gnutls_session_t SESSION, const char * HOSTNAME, const char * PROTO, unsigned int PORT, unsigned int SFLAGS, unsigned int VFLAGS, unsigned int * VERIFY)'
'CONST CHAR * *note dane_strerror:: (int ERROR)'

Note that the 'dane_state_t' structure that is accepted by both
verification functions is optional.  It is required when many queries
are performed to facilitate caching.  The following flags are returned
by the verify functions to indicate the status of the verification.

'DANE_VERIFY_CA_CONSTRAINTS_VIOLATED'
     The CA constraints were violated.
'DANE_VERIFY_CERT_DIFFERS'
     The certificate obtained via DNS differs.
'DANE_VERIFY_UNKNOWN_DANE_INFO'
     No known DANE data was found in the DNS record.

Figure 6.2: The DANE verification status flags.

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


File: gnutls.info,  Node: Parameter generation,  Next: Deriving keys for other applications/protocols,  Prev: Certificate verification,  Up: Advanced topics

6.12.3 Parameter generation
---------------------------

Several TLS ciphersuites require additional parameters that need to be
generated or provided by the application.  The Diffie-Hellman based
ciphersuites (ANON-DH or DHE), require the group parameters to be
provided.  Those can either be be generated on the fly using *note
gnutls_dh_params_generate2:: or imported from pregenerated data using
*note gnutls_dh_params_import_pkcs3::.  The parameters can be used in a
TLS session by calling *note gnutls_certificate_set_dh_params:: or *note
gnutls_anon_set_server_dh_params:: for anonymous sessions.

'INT *note gnutls_dh_params_generate2:: (gnutls_dh_params_t DPARAMS, unsigned int BITS)'
'INT *note gnutls_dh_params_import_pkcs3:: (gnutls_dh_params_t PARAMS, const gnutls_datum_t * PKCS3_PARAMS, gnutls_x509_crt_fmt_t FORMAT)'
'VOID *note gnutls_certificate_set_dh_params:: (gnutls_certificate_credentials_t RES, gnutls_dh_params_t DH_PARAMS)'
'VOID *note gnutls_anon_set_server_dh_params:: (gnutls_anon_server_credentials_t RES, gnutls_dh_params_t DH_PARAMS)'

Due to the time-consuming calculations required for the generation of
Diffie-Hellman parameters we suggest against performing generation of
them within an application.  The 'certtool' tool can be used to generate
or export known safe values that can be stored in code or in a
configuration file to provide the ability to replace.  We also recommend
the usage of *note gnutls_sec_param_to_pk_bits:: (see *note Selecting
cryptographic key sizes::) to determine the bit size of the generated
parameters.

Note that the information stored in the generated PKCS #3 structure
changed with GnuTLS 3.0.9.  Since that version the 'privateValueLength'
member of the structure is set, allowing the server utilizing the
parameters to use keys of the size of the security parameter.  This
provides better performance in key exchange.

To allow renewal of the parameters within an application without
accessing the credentials, which are a shared structure, an alternative
interface is available using a callback function.

 -- Function: void gnutls_certificate_set_params_function
          (gnutls_certificate_credentials_t RES, gnutls_params_function
          * FUNC)
     RES: is a gnutls_certificate_credentials_t structure

     FUNC: is the function to be called

     This function will set a callback in order for the server to get
     the Diffie-Hellman or RSA parameters for certificate
     authentication.  The callback should return 'GNUTLS_E_SUCCESS' (0)
     on success.


File: gnutls.info,  Node: Deriving keys for other applications/protocols,  Next: Channel Bindings,  Prev: Parameter generation,  Up: Advanced topics

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

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

The API to use is *note gnutls_prf::.  The function needs to be provided
with a label, and additional context data to mix in the 'extra'
parameter.  Moreover, the API allows to switch the mix of the client and
server random nonces, using the 'server_random_first' parameter.  In
typical uses you don't need it, so a zero value should be provided in
'server_random_first'.

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

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

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

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

If you don't want to use the RFC5705 interface and not mix in the client
and server random nonces, there is a low-level TLS PRF interface called
*note gnutls_prf_raw::.


File: gnutls.info,  Node: Channel Bindings,  Next: Interoperability,  Prev: Deriving keys for other applications/protocols,  Up: Advanced topics

6.12.5 Channel bindings
-----------------------

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

In GnuTLS you can extract a channel binding using the *note
gnutls_session_channel_binding:: function.  Currently only the type
'GNUTLS_CB_TLS_UNIQUE' is supported, which corresponds to the
'tls-unique' channel binding for TLS defined in [_RFC5929_].

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

     {
       gnutls_datum_t cb;
       int rc;

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


File: gnutls.info,  Node: Interoperability,  Next: Compatibility with the OpenSSL library,  Prev: Channel Bindings,  Up: Advanced topics

6.12.6 Interoperability
-----------------------

The TLS protocols support many ciphersuites, extensions and version
numbers.  As a result, few implementations are not able to properly
interoperate once faced with extensions or version protocols they do not
support and understand.  The TLS protocol allows for a graceful
downgrade to the commonly supported options, but practice shows it is
not always implemented correctly.

Because there is no way to achieve maximum interoperability with broken
peers without sacrificing security, GnuTLS ignores such peers by
default.  This might not be acceptable in cases where maximum
compatibility is required.  Thus we allow enabling compatibility with
broken peers using priority strings (see *note Priority Strings::).  A
conservative priority string that would disable certain TLS protocol
options that are known to cause compatibility problems, is shown below.
NORMAL:%COMPAT

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


File: gnutls.info,  Node: Compatibility with the OpenSSL library,  Prev: Interoperability,  Up: Advanced topics

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

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

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

   * Error handling is not thread safe.


File: gnutls.info,  Node: GnuTLS application examples,  Next: Using GnuTLS as a cryptographic library,  Prev: How to use GnuTLS in applications,  Up: Top

7 GnuTLS application examples
*****************************

In this chapter several examples of real-world use cases are listed.
The examples are simplified to promote readability and contain little or
no error checking.

* Menu:

* Client examples::
* Server examples::
* OCSP example::
* Miscellaneous examples::


File: gnutls.info,  Node: Client examples,  Next: Server examples,  Up: GnuTLS application examples

7.1 Client examples
===================

This section contains examples of TLS and SSL clients, using GnuTLS.
Note that some of the examples require functions implemented by another
example.

* Menu:

* Simple client example with X.509 certificate support::
* Simple client example with SSH-style certificate verification::
* Simple client example with anonymous authentication::
* Simple Datagram TLS client example::
* Obtaining session information::
* Using a callback to select the certificate to use::
* Verifying a certificate::
* Client using a smart card with TLS::
* Client with Resume capability example::
* Simple client example with SRP authentication::
* Simple client example in C++::
* Helper functions for TCP connections::
* Helper functions for UDP connections::


File: gnutls.info,  Node: Simple client example with X.509 certificate support,  Next: Simple client example with SSH-style certificate verification,  Up: Client examples

7.1.1 Simple client example with X.509 certificate support
----------------------------------------------------------

Let's assume now that we want to create a TCP client which communicates
with servers that use X.509 or OpenPGP certificate authentication.  The
following client is a very simple TLS client, which uses the high level
verification functions for certificates, but does not support session
resumption.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "examples.h"

/* A very basic TLS client, with X.509 authentication and server certificate
 * verification. Note that error checking for missing files etc. is omitted
 * for simplicity.
 */

#define MAX_BUF 1024
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define MSG "GET / HTTP/1.0\r\n\r\n"

extern int tcp_connect(void);
extern void tcp_close(int sd);
static int _verify_certificate_callback(gnutls_session_t session);

int main(void)
{
        int ret, sd, ii;
        gnutls_session_t session;
        char buffer[MAX_BUF + 1];
        const char *err;
        gnutls_certificate_credentials_t xcred;

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        /* X509 stuff */
        gnutls_certificate_allocate_credentials(&xcred);

        /* sets the trusted cas file
         */
        gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);
        gnutls_certificate_set_verify_function(xcred,
                                               _verify_certificate_callback);

        /* If client holds a certificate it can be set using the following:
         *
         gnutls_certificate_set_x509_key_file (xcred,
         "cert.pem", "key.pem",
         GNUTLS_X509_FMT_PEM);
         */

        /* Initialize TLS session
         */
        gnutls_init(&session, GNUTLS_CLIENT);

        gnutls_session_set_ptr(session, (void *) "my_host_name");

        gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name",
                               strlen("my_host_name"));

        /* use default priorities */
        gnutls_set_default_priority(session);
#if 0
	/* if more fine-graned control is required */
        ret = gnutls_priority_set_direct(session,
                                         "NORMAL", &err);
        if (ret < 0) {
                if (ret == GNUTLS_E_INVALID_REQUEST) {
                        fprintf(stderr, "Syntax error at: %s\n", err);
                }
                exit(1);
        }
#endif

        /* put the x509 credentials to the current session
         */
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);

        /* connect to the peer
         */
        sd = tcp_connect();

        gnutls_transport_set_int(session, sd);
        gnutls_handshake_set_timeout(session,
                                     GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

        /* Perform the TLS handshake
         */
        do {
                ret = gnutls_handshake(session);
        }
        while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

        if (ret < 0) {
                fprintf(stderr, "*** Handshake failed\n");
                gnutls_perror(ret);
                goto end;
        } else {
                char *desc;

                desc = gnutls_session_get_desc(session);
                printf("- Session info: %s\n", desc);
                gnutls_free(desc);
        }

        gnutls_record_send(session, MSG, strlen(MSG));

        ret = gnutls_record_recv(session, buffer, MAX_BUF);
        if (ret == 0) {
                printf("- Peer has closed the TLS connection\n");
                goto end;
        } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
                fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
        } else if (ret < 0) {
                fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
                goto end;
        }

        if (ret > 0) {
                printf("- Received %d bytes: ", ret);
                for (ii = 0; ii < ret; ii++) {
                        fputc(buffer[ii], stdout);
                }
                fputs("\n", stdout);
        }

        gnutls_bye(session, GNUTLS_SHUT_RDWR);

      end:

        tcp_close(sd);

        gnutls_deinit(session);

        gnutls_certificate_free_credentials(xcred);

        gnutls_global_deinit();

        return 0;
}

/* This function will verify the peer's certificate, and check
 * if the hostname matches, as well as the activation, expiration dates.
 */
static int _verify_certificate_callback(gnutls_session_t session)
{
        unsigned int status;
        int ret, type;
        const char *hostname;
        gnutls_datum_t out;

        /* read hostname */
        hostname = gnutls_session_get_ptr(session);

        /* This verification function uses the trusted CAs in the credentials
         * structure. So you must have installed one or more CA certificates.
         */

         /* The following demonstrate two different verification functions,
          * the more flexible gnutls_certificate_verify_peers(), as well
          * as the old gnutls_certificate_verify_peers3(). */
#if 1
        {
        gnutls_typed_vdata_st data[2];

        memset(data, 0, sizeof(data));

        data[0].type = GNUTLS_DT_DNS_HOSTNAME;
        data[0].data = (void*)hostname;

        data[1].type = GNUTLS_DT_KEY_PURPOSE_OID;
        data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER;

        ret = gnutls_certificate_verify_peers(session, data, 2,
					      &status);
        }
#else
        ret = gnutls_certificate_verify_peers3(session, hostname,
					       &status);
#endif
        if (ret < 0) {
                printf("Error\n");
                return GNUTLS_E_CERTIFICATE_ERROR;
        }

        type = gnutls_certificate_type_get(session);

        ret =
            gnutls_certificate_verification_status_print(status, type,
                                                         &out, 0);
        if (ret < 0) {
                printf("Error\n");
                return GNUTLS_E_CERTIFICATE_ERROR;
        }

        printf("%s", out.data);

        gnutls_free(out.data);

        if (status != 0)        /* Certificate is not trusted */
                return GNUTLS_E_CERTIFICATE_ERROR;

        /* notify gnutls to continue handshake normally */
        return 0;
}


File: gnutls.info,  Node: Simple client example with SSH-style certificate verification,  Next: Simple client example with anonymous authentication,  Prev: Simple client example with X.509 certificate support,  Up: Client examples

7.1.2 Simple client example with SSH-style certificate verification
-------------------------------------------------------------------

This is an alternative verification function that will use the X.509
certificate authorities for verification, but also assume an trust on
first use (SSH-like) authentication system.  That is the user is
prompted on unknown public keys and known public keys are considered
trusted.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "examples.h"

/* This function will verify the peer's certificate, check
 * if the hostname matches. In addition it will perform an
 * SSH-style authentication, where ultimately trusted keys
 * are only the keys that have been seen before.
 */
int _ssh_verify_certificate_callback(gnutls_session_t session)
{
        unsigned int status;
        const gnutls_datum_t *cert_list;
        unsigned int cert_list_size;
        int ret, type;
        gnutls_datum_t out;
        const char *hostname;

        /* read hostname */
        hostname = gnutls_session_get_ptr(session);

        /* This verification function uses the trusted CAs in the credentials
         * structure. So you must have installed one or more CA certificates.
         */
        ret = gnutls_certificate_verify_peers3(session, hostname, &status);
        if (ret < 0) {
                printf("Error\n");
                return GNUTLS_E_CERTIFICATE_ERROR;
        }

        type = gnutls_certificate_type_get(session);

        ret =
            gnutls_certificate_verification_status_print(status, type,
                                                         &out, 0);
        if (ret < 0) {
                printf("Error\n");
                return GNUTLS_E_CERTIFICATE_ERROR;
        }

        printf("%s", out.data);

        gnutls_free(out.data);

        if (status != 0)        /* Certificate is not trusted */
                return GNUTLS_E_CERTIFICATE_ERROR;

        /* Do SSH verification */
        cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
        if (cert_list == NULL) {
                printf("No certificate was found!\n");
                return GNUTLS_E_CERTIFICATE_ERROR;
        }

        /* service may be obtained alternatively using getservbyport() */
        ret = gnutls_verify_stored_pubkey(NULL, NULL, hostname, "https",
                                          type, &cert_list[0], 0);
        if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
                printf("Host %s is not known.", hostname);
                if (status == 0)
                        printf("Its certificate is valid for %s.\n",
                               hostname);

                /* the certificate must be printed and user must be asked on
                 * whether it is trustworthy. --see gnutls_x509_crt_print() */

                /* if not trusted */
                return GNUTLS_E_CERTIFICATE_ERROR;
        } else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) {
                printf
                    ("Warning: host %s is known but has another key associated.",
                     hostname);
                printf
                    ("It might be that the server has multiple keys, or you are under attack\n");
                if (status == 0)
                        printf("Its certificate is valid for %s.\n",
                               hostname);

                /* the certificate must be printed and user must be asked on
                 * whether it is trustworthy. --see gnutls_x509_crt_print() */

                /* if not trusted */
                return GNUTLS_E_CERTIFICATE_ERROR;
        } else if (ret < 0) {
                printf("gnutls_verify_stored_pubkey: %s\n",
                       gnutls_strerror(ret));
                return ret;
        }

        /* user trusts the key -> store it */
        if (ret != 0) {
                ret = gnutls_store_pubkey(NULL, NULL, hostname, "https",
                                          type, &cert_list[0], 0, 0);
                if (ret < 0)
                        printf("gnutls_store_pubkey: %s\n",
                               gnutls_strerror(ret));
        }

        /* notify gnutls to continue handshake normally */
        return 0;
}


File: gnutls.info,  Node: Simple client example with anonymous authentication,  Next: Simple Datagram TLS client example,  Prev: Simple client example with SSH-style certificate verification,  Up: Client examples

7.1.3 Simple client example with anonymous authentication
---------------------------------------------------------

The simplest client using TLS is the one that doesn't do any
authentication.  This means no external certificates or passwords are
needed to set up the connection.  As could be expected, the connection
is vulnerable to man-in-the-middle (active or redirection) attacks.
However, the data are integrity protected and encrypted from passive
eavesdroppers.

Note that due to the vulnerable nature of this method very few public
servers support it.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>

/* A very basic TLS client, with anonymous authentication.
 */

#define MAX_BUF 1024
#define MSG "GET / HTTP/1.0\r\n\r\n"

extern int tcp_connect(void);
extern void tcp_close(int sd);

int main(void)
{
        int ret, sd, ii;
        gnutls_session_t session;
        char buffer[MAX_BUF + 1];
        gnutls_anon_client_credentials_t anoncred;
        /* Need to enable anonymous KX specifically. */

        gnutls_global_init();

        gnutls_anon_allocate_client_credentials(&anoncred);

        /* Initialize TLS session
         */
        gnutls_init(&session, GNUTLS_CLIENT);

        /* Use default priorities */
        gnutls_priority_set_direct(session,
                                   "PERFORMANCE:+ANON-ECDH:+ANON-DH",
                                   NULL);

        /* put the anonymous credentials to the current session
         */
        gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);

        /* connect to the peer
         */
        sd = tcp_connect();

        gnutls_transport_set_int(session, sd);
        gnutls_handshake_set_timeout(session,
                                     GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

        /* Perform the TLS handshake
         */
        do {
                ret = gnutls_handshake(session);
        }
        while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

        if (ret < 0) {
                fprintf(stderr, "*** Handshake failed\n");
                gnutls_perror(ret);
                goto end;
        } else {
                char *desc;

                desc = gnutls_session_get_desc(session);
                printf("- Session info: %s\n", desc);
                gnutls_free(desc);
        }

        gnutls_record_send(session, MSG, strlen(MSG));

        ret = gnutls_record_recv(session, buffer, MAX_BUF);
        if (ret == 0) {
                printf("- Peer has closed the TLS connection\n");
                goto end;
        } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
                fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
        } else if (ret < 0) {
                fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
                goto end;
        }

        if (ret > 0) {
                printf("- Received %d bytes: ", ret);
                for (ii = 0; ii < ret; ii++) {
                        fputc(buffer[ii], stdout);
                }
                fputs("\n", stdout);
        }

        gnutls_bye(session, GNUTLS_SHUT_RDWR);

      end:

        tcp_close(sd);

        gnutls_deinit(session);

        gnutls_anon_free_client_credentials(anoncred);

        gnutls_global_deinit();

        return 0;
}


File: gnutls.info,  Node: Simple Datagram TLS client example,  Next: Obtaining session information,  Prev: Simple client example with anonymous authentication,  Up: Client examples

7.1.4 Simple datagram TLS client example
----------------------------------------

This is a client that uses UDP to connect to a server.  This is the DTLS
equivalent to the TLS example with X.509 certificates.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>

/* A very basic Datagram TLS client, over UDP with X.509 authentication.
 */

#define MAX_BUF 1024
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define MSG "GET / HTTP/1.0\r\n\r\n"

extern int udp_connect(void);
extern void udp_close(int sd);
extern int verify_certificate_callback(gnutls_session_t session);

int main(void)
{
        int ret, sd, ii;
        gnutls_session_t session;
        char buffer[MAX_BUF + 1];
        const char *err;
        gnutls_certificate_credentials_t xcred;

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        /* X509 stuff */
        gnutls_certificate_allocate_credentials(&xcred);

        /* sets the trusted cas file */
        gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);
        gnutls_certificate_set_verify_function(xcred,
                                               verify_certificate_callback);

        /* Initialize TLS session */
        gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);

        /* Use default priorities */
        ret = gnutls_priority_set_direct(session,
                                         "NORMAL", &err);
        if (ret < 0) {
                if (ret == GNUTLS_E_INVALID_REQUEST) {
                        fprintf(stderr, "Syntax error at: %s\n", err);
                }
                exit(1);
        }

        /* put the x509 credentials to the current session */
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
        gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name",
                               strlen("my_host_name"));

        /* connect to the peer */
        sd = udp_connect();

        gnutls_transport_set_int(session, sd);

        /* set the connection MTU */
        gnutls_dtls_set_mtu(session, 1000);
        /* gnutls_dtls_set_timeouts(session, 1000, 60000); */

        /* Perform the TLS handshake */
        do {
                ret = gnutls_handshake(session);
        }
        while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
        /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET */

        if (ret < 0) {
                fprintf(stderr, "*** Handshake failed\n");
                gnutls_perror(ret);
                goto end;
        } else {
                char *desc;

                desc = gnutls_session_get_desc(session);
                printf("- Session info: %s\n", desc);
                gnutls_free(desc);
        }

        gnutls_record_send(session, MSG, strlen(MSG));

        ret = gnutls_record_recv(session, buffer, MAX_BUF);
        if (ret == 0) {
                printf("- Peer has closed the TLS connection\n");
                goto end;
        } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
                fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret));
        } else if (ret < 0) {
                fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
                goto end;
        }

        if (ret > 0) {
                printf("- Received %d bytes: ", ret);
                for (ii = 0; ii < ret; ii++) {
                        fputc(buffer[ii], stdout);
                }
                fputs("\n", stdout);
        }

        /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS
         * connections because the peer's closure message might
         * be lost */
        gnutls_bye(session, GNUTLS_SHUT_WR);

      end:

        udp_close(sd);

        gnutls_deinit(session);

        gnutls_certificate_free_credentials(xcred);

        gnutls_global_deinit();

        return 0;
}


File: gnutls.info,  Node: Obtaining session information,  Next: Using a callback to select the certificate to use,  Prev: Simple Datagram TLS client example,  Up: Client examples

7.1.5 Obtaining session information
-----------------------------------

Most of the times it is desirable to know the security properties of the
current established session.  This includes the underlying ciphers and
the protocols involved.  That is the purpose of the following function.
Note that this function will print meaningful values only if called
after a successful *note gnutls_handshake::.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>

#include "examples.h"

/* This function will print some details of the
 * given session.
 */
int print_info(gnutls_session_t session)
{
        const char *tmp;
        gnutls_credentials_type_t cred;
        gnutls_kx_algorithm_t kx;
        int dhe, ecdh;

        dhe = ecdh = 0;

        /* print the key exchange's algorithm name
         */
        kx = gnutls_kx_get(session);
        tmp = gnutls_kx_get_name(kx);
        printf("- Key Exchange: %s\n", tmp);

        /* Check the authentication type used and switch
         * to the appropriate.
         */
        cred = gnutls_auth_get_type(session);
        switch (cred) {
        case GNUTLS_CRD_IA:
                printf("- TLS/IA session\n");
                break;


#ifdef ENABLE_SRP
        case GNUTLS_CRD_SRP:
                printf("- SRP session with username %s\n",
                       gnutls_srp_server_get_username(session));
                break;
#endif

        case GNUTLS_CRD_PSK:
                /* This returns NULL in server side.
                 */
                if (gnutls_psk_client_get_hint(session) != NULL)
                        printf("- PSK authentication. PSK hint '%s'\n",
                               gnutls_psk_client_get_hint(session));
                /* This returns NULL in client side.
                 */
                if (gnutls_psk_server_get_username(session) != NULL)
                        printf("- PSK authentication. Connected as '%s'\n",
                               gnutls_psk_server_get_username(session));

                if (kx == GNUTLS_KX_ECDHE_PSK)
                        ecdh = 1;
                else if (kx == GNUTLS_KX_DHE_PSK)
                        dhe = 1;
                break;

        case GNUTLS_CRD_ANON:  /* anonymous authentication */

                printf("- Anonymous authentication.\n");
                if (kx == GNUTLS_KX_ANON_ECDH)
                        ecdh = 1;
                else if (kx == GNUTLS_KX_ANON_DH)
                        dhe = 1;
                break;

        case GNUTLS_CRD_CERTIFICATE:   /* certificate authentication */

                /* Check if we have been using ephemeral Diffie-Hellman.
                 */
                if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
                        dhe = 1;
                else if (kx == GNUTLS_KX_ECDHE_RSA
                         || kx == GNUTLS_KX_ECDHE_ECDSA)
                        ecdh = 1;

                /* if the certificate list is available, then
                 * print some information about it.
                 */
                print_x509_certificate_info(session);

        }                       /* switch */

        if (ecdh != 0)
                printf("- Ephemeral ECDH using curve %s\n",
                       gnutls_ecc_curve_get_name(gnutls_ecc_curve_get
                                                 (session)));
        else if (dhe != 0)
                printf("- Ephemeral DH using prime of %d bits\n",
                       gnutls_dh_get_prime_bits(session));

        /* print the protocol's name (ie TLS 1.0)
         */
        tmp =
            gnutls_protocol_get_name(gnutls_protocol_get_version(session));
        printf("- Protocol: %s\n", tmp);

        /* print the certificate type of the peer.
         * ie X.509
         */
        tmp =
            gnutls_certificate_type_get_name(gnutls_certificate_type_get
                                             (session));

        printf("- Certificate Type: %s\n", tmp);

        /* print the compression algorithm (if any)
         */
        tmp = gnutls_compression_get_name(gnutls_compression_get(session));
        printf("- Compression: %s\n", tmp);

        /* print the name of the cipher used.
         * ie 3DES.
         */
        tmp = gnutls_cipher_get_name(gnutls_cipher_get(session));
        printf("- Cipher: %s\n", tmp);

        /* Print the MAC algorithms name.
         * ie SHA1
         */
        tmp = gnutls_mac_get_name(gnutls_mac_get(session));
        printf("- MAC: %s\n", tmp);

        return 0;
}


File: gnutls.info,  Node: Using a callback to select the certificate to use,  Next: Verifying a certificate,  Prev: Obtaining session information,  Up: Client examples

7.1.6 Using a callback to select the certificate to use
-------------------------------------------------------

There are cases where a client holds several certificate and key pairs,
and may not want to load all of them in the credentials structure.  The
following example demonstrates the use of the certificate selection
callback.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/abstract.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* A TLS client that loads the certificate and key.
 */

#define MAX_BUF 1024
#define MSG "GET / HTTP/1.0\r\n\r\n"

#define CERT_FILE "cert.pem"
#define KEY_FILE "key.pem"
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"

extern int tcp_connect(void);
extern void tcp_close(int sd);

static int
cert_callback(gnutls_session_t session,
              const gnutls_datum_t * req_ca_rdn, int nreqs,
              const gnutls_pk_algorithm_t * sign_algos,
              int sign_algos_length, gnutls_pcert_st ** pcert,
              unsigned int *pcert_length, gnutls_privkey_t * pkey);

gnutls_pcert_st pcrt;
gnutls_privkey_t key;

/* Load the certificate and the private key.
 */
static void load_keys(void)
{
        int ret;
        gnutls_datum_t data;

        ret = gnutls_load_file(CERT_FILE, &data);
        if (ret < 0) {
                fprintf(stderr, "*** Error loading certificate file.\n");
                exit(1);
        }

        ret =
            gnutls_pcert_import_x509_raw(&pcrt, &data, GNUTLS_X509_FMT_PEM,
                                         0);
        if (ret < 0) {
                fprintf(stderr, "*** Error loading certificate file: %s\n",
                        gnutls_strerror(ret));
                exit(1);
        }

        gnutls_free(data.data);

        ret = gnutls_load_file(KEY_FILE, &data);
        if (ret < 0) {
                fprintf(stderr, "*** Error loading key file.\n");
                exit(1);
        }

        gnutls_privkey_init(&key);

        ret =
            gnutls_privkey_import_x509_raw(key, &data, GNUTLS_X509_FMT_PEM,
                                           NULL, 0);
        if (ret < 0) {
                fprintf(stderr, "*** Error loading key file: %s\n",
                        gnutls_strerror(ret));
                exit(1);
        }

        gnutls_free(data.data);
}

int main(void)
{
        int ret, sd, ii;
        gnutls_session_t session;
        gnutls_priority_t priorities_cache;
        char buffer[MAX_BUF + 1];
        gnutls_certificate_credentials_t xcred;

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        load_keys();

        /* X509 stuff */
        gnutls_certificate_allocate_credentials(&xcred);

        /* priorities */
        gnutls_priority_init(&priorities_cache,
                             "NORMAL", NULL);

        /* sets the trusted cas file
         */
        gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);

        gnutls_certificate_set_retrieve_function2(xcred, cert_callback);

        /* Initialize TLS session
         */
        gnutls_init(&session, GNUTLS_CLIENT);

        /* Use default priorities */
        gnutls_priority_set(session, priorities_cache);

        /* put the x509 credentials to the current session
         */
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);

        /* connect to the peer
         */
        sd = tcp_connect();

        gnutls_transport_set_int(session, sd);

        /* Perform the TLS handshake
         */
        ret = gnutls_handshake(session);

        if (ret < 0) {
                fprintf(stderr, "*** Handshake failed\n");
                gnutls_perror(ret);
                goto end;
        } else {
                char *desc;

                desc = gnutls_session_get_desc(session);
                printf("- Session info: %s\n", desc);
                gnutls_free(desc);
        }

        gnutls_record_send(session, MSG, strlen(MSG));

        ret = gnutls_record_recv(session, buffer, MAX_BUF);
        if (ret == 0) {
                printf("- Peer has closed the TLS connection\n");
                goto end;
        } else if (ret < 0) {
                fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
                goto end;
        }

        printf("- Received %d bytes: ", ret);
        for (ii = 0; ii < ret; ii++) {
                fputc(buffer[ii], stdout);
        }
        fputs("\n", stdout);

        gnutls_bye(session, GNUTLS_SHUT_RDWR);

      end:

        tcp_close(sd);

        gnutls_deinit(session);

        gnutls_certificate_free_credentials(xcred);
        gnutls_priority_deinit(priorities_cache);

        gnutls_global_deinit();

        return 0;
}



/* This callback should be associated with a session by calling
 * gnutls_certificate_client_set_retrieve_function( session, cert_callback),
 * before a handshake.
 */

static int
cert_callback(gnutls_session_t session,
              const gnutls_datum_t * req_ca_rdn, int nreqs,
              const gnutls_pk_algorithm_t * sign_algos,
              int sign_algos_length, gnutls_pcert_st ** pcert,
              unsigned int *pcert_length, gnutls_privkey_t * pkey)
{
        char issuer_dn[256];
        int i, ret;
        size_t len;
        gnutls_certificate_type_t type;

        /* Print the server's trusted CAs
         */
        if (nreqs > 0)
                printf("- Server's trusted authorities:\n");
        else
                printf
                    ("- Server did not send us any trusted authorities names.\n");

        /* print the names (if any) */
        for (i = 0; i < nreqs; i++) {
                len = sizeof(issuer_dn);
                ret = gnutls_x509_rdn_get(&req_ca_rdn[i], issuer_dn, &len);
                if (ret >= 0) {
                        printf("   [%d]: ", i);
                        printf("%s\n", issuer_dn);
                }
        }

        /* Select a certificate and return it.
         * The certificate must be of any of the "sign algorithms"
         * supported by the server.
         */
        type = gnutls_certificate_type_get(session);
        if (type == GNUTLS_CRT_X509) {
                *pcert_length = 1;
                *pcert = &pcrt;
                *pkey = key;
        } else {
                return -1;
        }

        return 0;

}


File: gnutls.info,  Node: Verifying a certificate,  Next: Client using a smart card with TLS,  Prev: Using a callback to select the certificate to use,  Up: Client examples

7.1.7 Verifying a certificate
-----------------------------

An example is listed below which uses the high level verification
functions to verify a given certificate list.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>

#include "examples.h"

/* All the available CRLs
 */
gnutls_x509_crl_t *crl_list;
int crl_list_size;

/* All the available trusted CAs
 */
gnutls_x509_crt_t *ca_list;
int ca_list_size;

static int print_details_func(gnutls_x509_crt_t cert,
                              gnutls_x509_crt_t issuer,
                              gnutls_x509_crl_t crl,
                              unsigned int verification_output);

/* This function will try to verify the peer's certificate chain, and
 * also check if the hostname matches.
 */
void
verify_certificate_chain(const char *hostname,
                         const gnutls_datum_t * cert_chain,
                         int cert_chain_length)
{
        int i;
        gnutls_x509_trust_list_t tlist;
        gnutls_x509_crt_t *cert;

        unsigned int output;

        /* Initialize the trusted certificate list. This should be done
         * once on initialization. gnutls_x509_crt_list_import2() and
         * gnutls_x509_crl_list_import2() can be used to load them.
         */
        gnutls_x509_trust_list_init(&tlist, 0);

        gnutls_x509_trust_list_add_cas(tlist, ca_list, ca_list_size, 0);
        gnutls_x509_trust_list_add_crls(tlist, crl_list, crl_list_size,
                                        GNUTLS_TL_VERIFY_CRL, 0);

        cert = malloc(sizeof(*cert) * cert_chain_length);

        /* Import all the certificates in the chain to
         * native certificate format.
         */
        for (i = 0; i < cert_chain_length; i++) {
                gnutls_x509_crt_init(&cert[i]);
                gnutls_x509_crt_import(cert[i], &cert_chain[i],
                                       GNUTLS_X509_FMT_DER);
        }

        gnutls_x509_trust_list_verify_named_crt(tlist, cert[0], hostname,
                                                strlen(hostname),
                                                GNUTLS_VERIFY_DISABLE_CRL_CHECKS,
                                                &output,
                                                print_details_func);

        /* if this certificate is not explicitly trusted verify against CAs
         */
        if (output != 0) {
                gnutls_x509_trust_list_verify_crt(tlist, cert,
                                                  cert_chain_length, 0,
                                                  &output,
                                                  print_details_func);
        }

        if (output & GNUTLS_CERT_INVALID) {
                fprintf(stderr, "Not trusted");

                if (output & GNUTLS_CERT_SIGNER_NOT_FOUND)
                        fprintf(stderr, ": no issuer was found");
                if (output & GNUTLS_CERT_SIGNER_NOT_CA)
                        fprintf(stderr, ": issuer is not a CA");
                if (output & GNUTLS_CERT_NOT_ACTIVATED)
                        fprintf(stderr, ": not yet activated\n");
                if (output & GNUTLS_CERT_EXPIRED)
                        fprintf(stderr, ": expired\n");

                fprintf(stderr, "\n");
        } else
                fprintf(stderr, "Trusted\n");

        /* Check if the name in the first certificate matches our destination!
         */
        if (!gnutls_x509_crt_check_hostname(cert[0], hostname)) {
                printf
                    ("The certificate's owner does not match hostname '%s'\n",
                     hostname);
        }

        gnutls_x509_trust_list_deinit(tlist, 1);

        return;
}

static int
print_details_func(gnutls_x509_crt_t cert,
                   gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl,
                   unsigned int verification_output)
{
        char name[512];
        char issuer_name[512];
        size_t name_size;
        size_t issuer_name_size;

        issuer_name_size = sizeof(issuer_name);
        gnutls_x509_crt_get_issuer_dn(cert, issuer_name,
                                      &issuer_name_size);

        name_size = sizeof(name);
        gnutls_x509_crt_get_dn(cert, name, &name_size);

        fprintf(stdout, "\tSubject: %s\n", name);
        fprintf(stdout, "\tIssuer: %s\n", issuer_name);

        if (issuer != NULL) {
                issuer_name_size = sizeof(issuer_name);
                gnutls_x509_crt_get_dn(issuer, issuer_name,
                                       &issuer_name_size);

                fprintf(stdout, "\tVerified against: %s\n", issuer_name);
        }

        if (crl != NULL) {
                issuer_name_size = sizeof(issuer_name);
                gnutls_x509_crl_get_issuer_dn(crl, issuer_name,
                                              &issuer_name_size);

                fprintf(stdout, "\tVerified against CRL of: %s\n",
                        issuer_name);
        }

        fprintf(stdout, "\tVerification output: %x\n\n",
                verification_output);

        return 0;
}


File: gnutls.info,  Node: Client using a smart card with TLS,  Next: Client with Resume capability example,  Prev: Verifying a certificate,  Up: Client examples

7.1.8 Using a smart card with TLS
---------------------------------

This example will demonstrate how to load keys and certificates from a
smart-card or any other PKCS #11 token, and use it in a TLS connection.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/pkcs11.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getpass.h>            /* for getpass() */

/* A TLS client that loads the certificate and key.
 */

#define MAX_BUF 1024
#define MSG "GET / HTTP/1.0\r\n\r\n"
#define MIN(x,y) (((x)<(y))?(x):(y))

#define CAFILE "/etc/ssl/certs/ca-certificates.crt"

/* The URLs of the objects can be obtained
 * using p11tool --list-all --login
 */
#define KEY_URL "pkcs11:manufacturer=SomeManufacturer;object=Private%20Key" \
  ";objecttype=private;id=%db%5b%3e%b5%72%33"
#define CERT_URL "pkcs11:manufacturer=SomeManufacturer;object=Certificate;" \
  "objecttype=cert;id=db%5b%3e%b5%72%33"

extern int tcp_connect(void);
extern void tcp_close(int sd);

static int
pin_callback(void *user, int attempt, const char *token_url,
             const char *token_label, unsigned int flags, char *pin,
             size_t pin_max)
{
        const char *password;
        int len;

        printf("PIN required for token '%s' with URL '%s'\n", token_label,
               token_url);
        if (flags & GNUTLS_PIN_FINAL_TRY)
                printf("*** This is the final try before locking!\n");
        if (flags & GNUTLS_PIN_COUNT_LOW)
                printf("*** Only few tries left before locking!\n");
        if (flags & GNUTLS_PIN_WRONG)
                printf("*** Wrong PIN\n");

        password = getpass("Enter pin: ");
        if (password == NULL || password[0] == 0) {
                fprintf(stderr, "No password given\n");
                exit(1);
        }

        len = MIN(pin_max - 1, strlen(password));
        memcpy(pin, password, len);
        pin[len] = 0;

        return 0;
}

int main(void)
{
        int ret, sd, ii;
        gnutls_session_t session;
        gnutls_priority_t priorities_cache;
        char buffer[MAX_BUF + 1];
        gnutls_certificate_credentials_t xcred;
        /* Allow connections to servers that have OpenPGP keys as well.
         */

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        /* The PKCS11 private key operations may require PIN.
         * Register a callback. */
        gnutls_pkcs11_set_pin_function(pin_callback, NULL);

        /* X509 stuff */
        gnutls_certificate_allocate_credentials(&xcred);

        /* priorities */
        gnutls_priority_init(&priorities_cache,
                             "NORMAL", NULL);

        /* sets the trusted cas file
         */
        gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);

        gnutls_certificate_set_x509_key_file(xcred, CERT_URL, KEY_URL,
                                             GNUTLS_X509_FMT_DER);

        /* Initialize TLS session
         */
        gnutls_init(&session, GNUTLS_CLIENT);

        /* Use default priorities */
        gnutls_priority_set(session, priorities_cache);

        /* put the x509 credentials to the current session
         */
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);

        /* connect to the peer
         */
        sd = tcp_connect();

        gnutls_transport_set_int(session, sd);

        /* Perform the TLS handshake
         */
        ret = gnutls_handshake(session);

        if (ret < 0) {
                fprintf(stderr, "*** Handshake failed\n");
                gnutls_perror(ret);
                goto end;
        } else {
                char *desc;

                desc = gnutls_session_get_desc(session);
                printf("- Session info: %s\n", desc);
                gnutls_free(desc);
        }

        gnutls_record_send(session, MSG, strlen(MSG));

        ret = gnutls_record_recv(session, buffer, MAX_BUF);
        if (ret == 0) {
                printf("- Peer has closed the TLS connection\n");
                goto end;
        } else if (ret < 0) {
                fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret));
                goto end;
        }

        printf("- Received %d bytes: ", ret);
        for (ii = 0; ii < ret; ii++) {
                fputc(buffer[ii], stdout);
        }
        fputs("\n", stdout);

        gnutls_bye(session, GNUTLS_SHUT_RDWR);

      end:

        tcp_close(sd);

        gnutls_deinit(session);

        gnutls_certificate_free_credentials(xcred);
        gnutls_priority_deinit(priorities_cache);

        gnutls_global_deinit();

        return 0;
}


File: gnutls.info,  Node: Client with Resume capability example,  Next: Simple client example with SRP authentication,  Prev: Client using a smart card with TLS,  Up: Client examples

7.1.9 Client with resume capability example
-------------------------------------------

This is a modification of the simple client example.  Here we
demonstrate the use of session resumption.  The client tries to connect
once using TLS, close the connection and then try to establish a new
connection using the previously negotiated data.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>

/* Those functions are defined in other examples.
 */
extern void check_alert(gnutls_session_t session, int ret);
extern int tcp_connect(void);
extern void tcp_close(int sd);

#define MAX_BUF 1024
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define MSG "GET / HTTP/1.0\r\n\r\n"

int main(void)
{
        int ret;
        int sd, ii;
        gnutls_session_t session;
        char buffer[MAX_BUF + 1];
        gnutls_certificate_credentials_t xcred;

        /* variables used in session resuming
         */
        int t;
        char *session_data = NULL;
        size_t session_data_size = 0;

        gnutls_global_init();

        /* X509 stuff */
        gnutls_certificate_allocate_credentials(&xcred);

        gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);

        for (t = 0; t < 2; t++) {       /* connect 2 times to the server */

                sd = tcp_connect();

                gnutls_init(&session, GNUTLS_CLIENT);

                gnutls_priority_set_direct(session,
                                           "PERFORMANCE:!ARCFOUR-128",
                                           NULL);

                gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
                                       xcred);

                if (t > 0) {
                        /* if this is not the first time we connect */
                        gnutls_session_set_data(session, session_data,
                                                session_data_size);
                        free(session_data);
                }

                gnutls_transport_set_int(session, sd);
                gnutls_handshake_set_timeout(session,
                                             GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

                /* Perform the TLS handshake
                 */
                do {
                        ret = gnutls_handshake(session);
                }
                while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

                if (ret < 0) {
                        fprintf(stderr, "*** Handshake failed\n");
                        gnutls_perror(ret);
                        goto end;
                } else {
                        printf("- Handshake was completed\n");
                }

                if (t == 0) {   /* the first time we connect */
                        /* get the session data size */
                        gnutls_session_get_data(session, NULL,
                                                &session_data_size);
                        session_data = malloc(session_data_size);

                        /* put session data to the session variable */
                        gnutls_session_get_data(session, session_data,
                                                &session_data_size);

                } else {        /* the second time we connect */

                        /* check if we actually resumed the previous session */
                        if (gnutls_session_is_resumed(session) != 0) {
                                printf("- Previous session was resumed\n");
                        } else {
                                fprintf(stderr,
                                        "*** Previous session was NOT resumed\n");
                        }
                }

                /* This function was defined in a previous example
                 */
                /* print_info(session); */

                gnutls_record_send(session, MSG, strlen(MSG));

                ret = gnutls_record_recv(session, buffer, MAX_BUF);
                if (ret == 0) {
                        printf("- Peer has closed the TLS connection\n");
                        goto end;
                } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
                        fprintf(stderr, "*** Warning: %s\n",
                                gnutls_strerror(ret));
                } else if (ret < 0) {
                        fprintf(stderr, "*** Error: %s\n",
                                gnutls_strerror(ret));
                        goto end;
                }

                if (ret > 0) {
                        printf("- Received %d bytes: ", ret);
                        for (ii = 0; ii < ret; ii++) {
                                fputc(buffer[ii], stdout);
                        }
                        fputs("\n", stdout);
                }

                gnutls_bye(session, GNUTLS_SHUT_RDWR);

              end:

                tcp_close(sd);

                gnutls_deinit(session);

        }                       /* for() */

        gnutls_certificate_free_credentials(xcred);

        gnutls_global_deinit();

        return 0;
}


File: gnutls.info,  Node: Simple client example with SRP authentication,  Next: Simple client example in C++,  Prev: Client with Resume capability example,  Up: Client examples

7.1.10 Simple client example with SRP authentication
----------------------------------------------------

The following client is a very simple SRP TLS client which connects to a
server and authenticates using a _username_ and a _password_.  The
server may authenticate itself using a certificate, and in that case it
has to be verified.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>

/* Those functions are defined in other examples.
 */
extern void check_alert(gnutls_session_t session, int ret);
extern int tcp_connect(void);
extern void tcp_close(int sd);

#define MAX_BUF 1024
#define USERNAME "user"
#define PASSWORD "pass"
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define MSG "GET / HTTP/1.0\r\n\r\n"

int main(void)
{
        int ret;
        int sd, ii;
        gnutls_session_t session;
        char buffer[MAX_BUF + 1];
        gnutls_srp_client_credentials_t srp_cred;
        gnutls_certificate_credentials_t cert_cred;

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        gnutls_srp_allocate_client_credentials(&srp_cred);
        gnutls_certificate_allocate_credentials(&cert_cred);

        gnutls_certificate_set_x509_trust_file(cert_cred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);
        gnutls_srp_set_client_credentials(srp_cred, USERNAME, PASSWORD);

        /* connects to server
         */
        sd = tcp_connect();

        /* Initialize TLS session
         */
        gnutls_init(&session, GNUTLS_CLIENT);


        /* Set the priorities.
         */
        gnutls_priority_set_direct(session,
                                   "NORMAL:+SRP:+SRP-RSA:+SRP-DSS",
                                   NULL);

        /* put the SRP credentials to the current session
         */
        gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred);

        gnutls_transport_set_int(session, sd);
        gnutls_handshake_set_timeout(session,
                                     GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

        /* Perform the TLS handshake
         */
        do {
                ret = gnutls_handshake(session);
        }
        while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

        if (ret < 0) {
                fprintf(stderr, "*** Handshake failed\n");
                gnutls_perror(ret);
                goto end;
        } else {
                char *desc;

                desc = gnutls_session_get_desc(session);
                printf("- Session info: %s\n", desc);
                gnutls_free(desc);
        }

        gnutls_record_send(session, MSG, strlen(MSG));

        ret = gnutls_record_recv(session, buffer, MAX_BUF);
        if (gnutls_error_is_fatal(ret) != 0 || ret == 0) {
                if (ret == 0) {
                        printf
                            ("- Peer has closed the GnuTLS connection\n");
                        goto end;
                } else {
                        fprintf(stderr, "*** Error: %s\n",
                                gnutls_strerror(ret));
                        goto end;
                }
        } else
                check_alert(session, ret);

        if (ret > 0) {
                printf("- Received %d bytes: ", ret);
                for (ii = 0; ii < ret; ii++) {
                        fputc(buffer[ii], stdout);
                }
                fputs("\n", stdout);
        }
        gnutls_bye(session, GNUTLS_SHUT_RDWR);

      end:

        tcp_close(sd);

        gnutls_deinit(session);

        gnutls_srp_free_client_credentials(srp_cred);
        gnutls_certificate_free_credentials(cert_cred);

        gnutls_global_deinit();

        return 0;
}


File: gnutls.info,  Node: Simple client example in C++,  Next: Helper functions for TCP connections,  Prev: Simple client example with SRP authentication,  Up: Client examples

7.1.11 Simple client example using the C++ API
----------------------------------------------

The following client is a simple example of a client client utilizing
the GnuTLS C++ API.

#include <config.h>
#include <iostream>
#include <stdexcept>
#include <gnutls/gnutls.h>
#include <gnutls/gnutlsxx.h>
#include <cstring> /* for strlen */

/* A very basic TLS client, with anonymous authentication.
 * written by Eduardo Villanueva Che.
 */

#define MAX_BUF 1024
#define SA struct sockaddr

#define CAFILE "ca.pem"
#define MSG "GET / HTTP/1.0\r\n\r\n"

extern "C"
{
    int tcp_connect(void);
    void tcp_close(int sd);
}


int main(void)
{
    int sd = -1;
    gnutls_global_init();

    try
    {

        /* Allow connections to servers that have OpenPGP keys as well.
         */
        gnutls::client_session session;

        /* X509 stuff */
        gnutls::certificate_credentials credentials;


        /* sets the trusted cas file
         */
        credentials.set_x509_trust_file(CAFILE, GNUTLS_X509_FMT_PEM);
        /* put the x509 credentials to the current session
         */
        session.set_credentials(credentials);

        /* Use default priorities */
        session.set_priority ("NORMAL", NULL);

        /* connect to the peer
         */
        sd = tcp_connect();
        session.set_transport_ptr((gnutls_transport_ptr_t) (ptrdiff_t)sd);

        /* Perform the TLS handshake
         */
        int ret = session.handshake();
        if (ret < 0)
        {
            throw std::runtime_error("Handshake failed");
        }
        else
        {
            std::cout << "- Handshake was completed" << std::endl;
        }

        session.send(MSG, strlen(MSG));
        char buffer[MAX_BUF + 1];
        ret = session.recv(buffer, MAX_BUF);
        if (ret == 0)
        {
            throw std::runtime_error("Peer has closed the TLS connection");
        }
        else if (ret < 0)
        {
            throw std::runtime_error(gnutls_strerror(ret));
        }

        std::cout << "- Received " << ret << " bytes:" << std::endl;
        std::cout.write(buffer, ret);
        std::cout << std::endl;

        session.bye(GNUTLS_SHUT_RDWR);
    }
    catch (std::exception &ex)
    {
        std::cerr << "Exception caught: " << ex.what() << std::endl;
    }

    if (sd != -1)
        tcp_close(sd);

    gnutls_global_deinit();

    return 0;
}


File: gnutls.info,  Node: Helper functions for TCP connections,  Next: Helper functions for UDP connections,  Prev: Simple client example in C++,  Up: Client examples

7.1.12 Helper functions for TCP connections
-------------------------------------------

Those helper function abstract away TCP connection handling from the
other examples.  It is required to build some examples.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

/* tcp.c */
int tcp_connect(void);
void tcp_close(int sd);

/* Connects to the peer and returns a socket
 * descriptor.
 */
extern int tcp_connect(void)
{
        const char *PORT = "5556";
        const char *SERVER = "127.0.0.1";
        int err, sd;
        struct sockaddr_in sa;

        /* connects to server
         */
        sd = socket(AF_INET, SOCK_STREAM, 0);

        memset(&sa, '\0', sizeof(sa));
        sa.sin_family = AF_INET;
        sa.sin_port = htons(atoi(PORT));
        inet_pton(AF_INET, SERVER, &sa.sin_addr);

        err = connect(sd, (struct sockaddr *) &sa, sizeof(sa));
        if (err < 0) {
                fprintf(stderr, "Connect error\n");
                exit(1);
        }

        return sd;
}

/* closes the given socket descriptor.
 */
extern void tcp_close(int sd)
{
        shutdown(sd, SHUT_RDWR);        /* no more receptions */
        close(sd);
}


File: gnutls.info,  Node: Helper functions for UDP connections,  Prev: Helper functions for TCP connections,  Up: Client examples

7.1.13 Helper functions for UDP connections
-------------------------------------------

The UDP helper functions abstract away UDP connection handling from the
other examples.  It is required to build the examples using UDP.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

/* udp.c */
int udp_connect(void);
void udp_close(int sd);

/* Connects to the peer and returns a socket
 * descriptor.
 */
extern int udp_connect(void)
{
        const char *PORT = "5557";
        const char *SERVER = "127.0.0.1";
        int err, sd, optval;
        struct sockaddr_in sa;

        /* connects to server
         */
        sd = socket(AF_INET, SOCK_DGRAM, 0);

        memset(&sa, '\0', sizeof(sa));
        sa.sin_family = AF_INET;
        sa.sin_port = htons(atoi(PORT));
        inet_pton(AF_INET, SERVER, &sa.sin_addr);

#if defined(IP_DONTFRAG)
        optval = 1;
        setsockopt(sd, IPPROTO_IP, IP_DONTFRAG,
                   (const void *) &optval, sizeof(optval));
#elif defined(IP_MTU_DISCOVER)
        optval = IP_PMTUDISC_DO;
        setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER,
                   (const void *) &optval, sizeof(optval));
#endif

        err = connect(sd, (struct sockaddr *) &sa, sizeof(sa));
        if (err < 0) {
                fprintf(stderr, "Connect error\n");
                exit(1);
        }

        return sd;
}

/* closes the given socket descriptor.
 */
extern void udp_close(int sd)
{
        close(sd);
}


File: gnutls.info,  Node: Server examples,  Next: OCSP example,  Prev: Client examples,  Up: GnuTLS application examples

7.2 Server examples
===================

This section contains examples of TLS and SSL servers, using GnuTLS.

* Menu:

* Echo server with X.509 authentication::
* Echo server with OpenPGP authentication::
* Echo server with SRP authentication::
* Echo server with anonymous authentication::
* DTLS echo server with X.509 authentication::


File: gnutls.info,  Node: Echo server with X.509 authentication,  Next: Echo server with OpenPGP authentication,  Up: Server examples

7.2.1 Echo server with X.509 authentication
-------------------------------------------

This example is a very simple echo server which supports X.509
authentication.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>

#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define CRLFILE "crl.pem"

/* The OCSP status file contains up to date information about revocation
 * of the server's certificate. That can be periodically be updated
 * using:
 * $ ocsptool --ask --load-cert your_cert.pem --load-issuer your_issuer.pem
 *            --load-signer your_issuer.pem --outfile ocsp-status.der
 */
#define OCSP_STATUS_FILE "ocsp-status.der"

/* This is a sample TLS 1.0 echo server, using X.509 authentication and
 * OCSP stapling support.
 */

#define MAX_BUF 1024
#define PORT 5556               /* listen to 5556 port */

/* These are global */
static gnutls_dh_params_t dh_params;

static int generate_dh_params(void)
{
        unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
                                                        GNUTLS_SEC_PARAM_LEGACY);

        /* Generate Diffie-Hellman parameters - for use with DHE
         * kx algorithms. When short bit length is used, it might
         * be wise to regenerate parameters often.
         */
        gnutls_dh_params_init(&dh_params);
        gnutls_dh_params_generate2(dh_params, bits);

        return 0;
}

int main(void)
{
        int listen_sd;
        int sd, ret;
        gnutls_certificate_credentials_t x509_cred;
        gnutls_priority_t priority_cache;
        struct sockaddr_in sa_serv;
        struct sockaddr_in sa_cli;
        socklen_t client_len;
        char topbuf[512];
        gnutls_session_t session;
        char buffer[MAX_BUF + 1];
        int optval = 1;

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        gnutls_certificate_allocate_credentials(&x509_cred);
        /* gnutls_certificate_set_x509_system_trust(xcred); */
        gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);

        gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE,
                                             GNUTLS_X509_FMT_PEM);

        ret =
            gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE,
                                                 KEYFILE,
                                                 GNUTLS_X509_FMT_PEM);
        if (ret < 0) {
                printf("No certificate or key were found\n");
                exit(1);
        }

        /* loads an OCSP status request if available */
        gnutls_certificate_set_ocsp_status_request_file(x509_cred,
                                                        OCSP_STATUS_FILE,
                                                        0);

        generate_dh_params();

        gnutls_priority_init(&priority_cache,
                             "PERFORMANCE:%SERVER_PRECEDENCE", NULL);


        gnutls_certificate_set_dh_params(x509_cred, dh_params);

        /* Socket operations
         */
        listen_sd = socket(AF_INET, SOCK_STREAM, 0);

        memset(&sa_serv, '\0', sizeof(sa_serv));
        sa_serv.sin_family = AF_INET;
        sa_serv.sin_addr.s_addr = INADDR_ANY;
        sa_serv.sin_port = htons(PORT); /* Server Port number */

        setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
                   sizeof(int));

        bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv));

        listen(listen_sd, 1024);

        printf("Server ready. Listening to port '%d'.\n\n", PORT);

        client_len = sizeof(sa_cli);
        for (;;) {
                gnutls_init(&session, GNUTLS_SERVER);
                gnutls_priority_set(session, priority_cache);
                gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
                                       x509_cred);

                /* We don't request any certificate from the client.
                 * If we did we would need to verify it. One way of
                 * doing that is shown in the "Verifying a certificate"
                 * example.
                 */
                gnutls_certificate_server_set_request(session,
                                                      GNUTLS_CERT_IGNORE);

                sd = accept(listen_sd, (struct sockaddr *) &sa_cli,
                            &client_len);

                printf("- connection from %s, port %d\n",
                       inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf,
                                 sizeof(topbuf)), ntohs(sa_cli.sin_port));

                gnutls_transport_set_int(session, sd);

                do {
                        ret = gnutls_handshake(session);
                }
                while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

                if (ret < 0) {
                        close(sd);
                        gnutls_deinit(session);
                        fprintf(stderr,
                                "*** Handshake has failed (%s)\n\n",
                                gnutls_strerror(ret));
                        continue;
                }
                printf("- Handshake was completed\n");

                /* see the Getting peer's information example */
                /* print_info(session); */

                for (;;) {
                        ret = gnutls_record_recv(session, buffer, MAX_BUF);

                        if (ret == 0) {
                                printf
                                    ("\n- Peer has closed the GnuTLS connection\n");
                                break;
                        } else if (ret < 0
                                   && gnutls_error_is_fatal(ret) == 0) {
                                fprintf(stderr, "*** Warning: %s\n",
                                        gnutls_strerror(ret));
                        } else if (ret < 0) {
                                fprintf(stderr, "\n*** Received corrupted "
                                        "data(%d). Closing the connection.\n\n",
                                        ret);
                                break;
                        } else if (ret > 0) {
                                /* echo data back to the client
                                 */
                                gnutls_record_send(session, buffer, ret);
                        }
                }
                printf("\n");
                /* do not wait for the peer to close the connection.
                 */
                gnutls_bye(session, GNUTLS_SHUT_WR);

                close(sd);
                gnutls_deinit(session);

        }
        close(listen_sd);

        gnutls_certificate_free_credentials(x509_cred);
        gnutls_priority_deinit(priority_cache);

        gnutls_global_deinit();

        return 0;

}


File: gnutls.info,  Node: Echo server with OpenPGP authentication,  Next: Echo server with SRP authentication,  Prev: Echo server with X.509 authentication,  Up: Server examples

7.2.2 Echo server with OpenPGP authentication
---------------------------------------------

The following example is an echo server which supports OpenPGP key
authentication.  You can easily combine this functionality --that is
have a server that supports both X.509 and OpenPGP certificates-- but we
separated them to keep these examples as simple as possible.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/openpgp.h>

#define KEYFILE "secret.asc"
#define CERTFILE "public.asc"
#define RINGFILE "ring.gpg"

/* This is a sample TLS 1.0-OpenPGP echo server.
 */


#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}
#define MAX_BUF 1024
#define PORT 5556               /* listen to 5556 port */

/* These are global */
gnutls_dh_params_t dh_params;

static int generate_dh_params(void)
{
        unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
                                                        GNUTLS_SEC_PARAM_LEGACY);

        /* Generate Diffie-Hellman parameters - for use with DHE
         * kx algorithms. These should be discarded and regenerated
         * once a day, once a week or once a month. Depending on the
         * security requirements.
         */
        gnutls_dh_params_init(&dh_params);
        gnutls_dh_params_generate2(dh_params, bits);

        return 0;
}

int main(void)
{
        int err, listen_sd;
        int sd, ret;
        struct sockaddr_in sa_serv;
        struct sockaddr_in sa_cli;
        socklen_t client_len;
        char topbuf[512];
        gnutls_session_t session;
        gnutls_certificate_credentials_t cred;
        char buffer[MAX_BUF + 1];
        int optval = 1;
        char name[256];

        strcpy(name, "Echo Server");

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        gnutls_certificate_allocate_credentials(&cred);
        gnutls_certificate_set_openpgp_keyring_file(cred, RINGFILE,
                                                    GNUTLS_OPENPGP_FMT_BASE64);

        gnutls_certificate_set_openpgp_key_file(cred, CERTFILE, KEYFILE,
                                                GNUTLS_OPENPGP_FMT_BASE64);

        generate_dh_params();

        gnutls_certificate_set_dh_params(cred, dh_params);

        /* Socket operations
         */
        listen_sd = socket(AF_INET, SOCK_STREAM, 0);
        SOCKET_ERR(listen_sd, "socket");

        memset(&sa_serv, '\0', sizeof(sa_serv));
        sa_serv.sin_family = AF_INET;
        sa_serv.sin_addr.s_addr = INADDR_ANY;
        sa_serv.sin_port = htons(PORT); /* Server Port number */

        setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
                   sizeof(int));

        err =
            bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv));
        SOCKET_ERR(err, "bind");
        err = listen(listen_sd, 1024);
        SOCKET_ERR(err, "listen");

        printf("%s ready. Listening to port '%d'.\n\n", name, PORT);

        client_len = sizeof(sa_cli);
        for (;;) {
                gnutls_init(&session, GNUTLS_SERVER);
                gnutls_priority_set_direct(session,
                                           "NORMAL:+CTYPE-OPENPGP", NULL);

                /* request client certificate if any.
                 */
                gnutls_certificate_server_set_request(session,
                                                      GNUTLS_CERT_REQUEST);

                sd = accept(listen_sd, (struct sockaddr *) &sa_cli,
                            &client_len);

                printf("- connection from %s, port %d\n",
                       inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf,
                                 sizeof(topbuf)), ntohs(sa_cli.sin_port));

                gnutls_transport_set_int(session, sd);
                ret = gnutls_handshake(session);
                if (ret < 0) {
                        close(sd);
                        gnutls_deinit(session);
                        fprintf(stderr,
                                "*** Handshake has failed (%s)\n\n",
                                gnutls_strerror(ret));
                        continue;
                }
                printf("- Handshake was completed\n");

                /* see the Getting peer's information example */
                /* print_info(session); */

                for (;;) {
                        ret = gnutls_record_recv(session, buffer, MAX_BUF);

                        if (ret == 0) {
                                printf
                                    ("\n- Peer has closed the GnuTLS connection\n");
                                break;
                        } else if (ret < 0
                                   && gnutls_error_is_fatal(ret) == 0) {
                                fprintf(stderr, "*** Warning: %s\n",
                                        gnutls_strerror(ret));
                        } else if (ret < 0) {
                                fprintf(stderr, "\n*** Received corrupted "
                                        "data(%d). Closing the connection.\n\n",
                                        ret);
                                break;
                        } else if (ret > 0) {
                                /* echo data back to the client
                                 */
                                gnutls_record_send(session, buffer, ret);
                        }
                }
                printf("\n");
                /* do not wait for the peer to close the connection.
                 */
                gnutls_bye(session, GNUTLS_SHUT_WR);

                close(sd);
                gnutls_deinit(session);

        }
        close(listen_sd);

        gnutls_certificate_free_credentials(cred);

        gnutls_global_deinit();

        return 0;

}


File: gnutls.info,  Node: Echo server with SRP authentication,  Next: Echo server with anonymous authentication,  Prev: Echo server with OpenPGP authentication,  Up: Server examples

7.2.3 Echo server with SRP authentication
-----------------------------------------

This is a server which supports SRP authentication.  It is also possible
to combine this functionality with a certificate server.  Here it is
separate for simplicity.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>

#define SRP_PASSWD "tpasswd"
#define SRP_PASSWD_CONF "tpasswd.conf"

#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"

/* This is a sample TLS-SRP echo server.
 */

#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}
#define MAX_BUF 1024
#define PORT 5556               /* listen to 5556 port */

int main(void)
{
        int err, listen_sd;
        int sd, ret;
        struct sockaddr_in sa_serv;
        struct sockaddr_in sa_cli;
        socklen_t client_len;
        char topbuf[512];
        gnutls_session_t session;
        gnutls_srp_server_credentials_t srp_cred;
        gnutls_certificate_credentials_t cert_cred;
        char buffer[MAX_BUF + 1];
        int optval = 1;
        char name[256];

        strcpy(name, "Echo Server");

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        /* SRP_PASSWD a password file (created with the included srptool utility)
         */
        gnutls_srp_allocate_server_credentials(&srp_cred);
        gnutls_srp_set_server_credentials_file(srp_cred, SRP_PASSWD,
                                               SRP_PASSWD_CONF);

        gnutls_certificate_allocate_credentials(&cert_cred);
        gnutls_certificate_set_x509_trust_file(cert_cred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);
        gnutls_certificate_set_x509_key_file(cert_cred, CERTFILE, KEYFILE,
                                             GNUTLS_X509_FMT_PEM);

        /* TCP socket operations
         */
        listen_sd = socket(AF_INET, SOCK_STREAM, 0);
        SOCKET_ERR(listen_sd, "socket");

        memset(&sa_serv, '\0', sizeof(sa_serv));
        sa_serv.sin_family = AF_INET;
        sa_serv.sin_addr.s_addr = INADDR_ANY;
        sa_serv.sin_port = htons(PORT); /* Server Port number */

        setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
                   sizeof(int));

        err =
            bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv));
        SOCKET_ERR(err, "bind");
        err = listen(listen_sd, 1024);
        SOCKET_ERR(err, "listen");

        printf("%s ready. Listening to port '%d'.\n\n", name, PORT);

        client_len = sizeof(sa_cli);
        for (;;) {
                gnutls_init(&session, GNUTLS_SERVER);
                gnutls_priority_set_direct(session,
                                           "NORMAL"
                                           ":-KX-ALL:+SRP:+SRP-DSS:+SRP-RSA",
                                           NULL);
                gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred);
                /* for the certificate authenticated ciphersuites.
                 */
                gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
                                       cert_cred);

                /* We don't request any certificate from the client.
                 * If we did we would need to verify it. One way of
                 * doing that is shown in the "Verifying a certificate"
                 * example.
                 */
                gnutls_certificate_server_set_request(session,
                                                      GNUTLS_CERT_IGNORE);

                sd = accept(listen_sd, (struct sockaddr *) &sa_cli,
                            &client_len);

                printf("- connection from %s, port %d\n",
                       inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf,
                                 sizeof(topbuf)), ntohs(sa_cli.sin_port));

                gnutls_transport_set_int(session, sd);

                do {
                        ret = gnutls_handshake(session);
                }
                while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

                if (ret < 0) {
                        close(sd);
                        gnutls_deinit(session);
                        fprintf(stderr,
                                "*** Handshake has failed (%s)\n\n",
                                gnutls_strerror(ret));
                        continue;
                }
                printf("- Handshake was completed\n");
                printf("- User %s was connected\n",
                       gnutls_srp_server_get_username(session));

                /* print_info(session); */

                for (;;) {
                        ret = gnutls_record_recv(session, buffer, MAX_BUF);

                        if (ret == 0) {
                                printf
                                    ("\n- Peer has closed the GnuTLS connection\n");
                                break;
                        } else if (ret < 0
                                   && gnutls_error_is_fatal(ret) == 0) {
                                fprintf(stderr, "*** Warning: %s\n",
                                        gnutls_strerror(ret));
                        } else if (ret < 0) {
                                fprintf(stderr, "\n*** Received corrupted "
                                        "data(%d). Closing the connection.\n\n",
                                        ret);
                                break;
                        } else if (ret > 0) {
                                /* echo data back to the client
                                 */
                                gnutls_record_send(session, buffer, ret);
                        }
                }
                printf("\n");
                /* do not wait for the peer to close the connection. */
                gnutls_bye(session, GNUTLS_SHUT_WR);

                close(sd);
                gnutls_deinit(session);

        }
        close(listen_sd);

        gnutls_srp_free_server_credentials(srp_cred);
        gnutls_certificate_free_credentials(cert_cred);

        gnutls_global_deinit();

        return 0;

}


File: gnutls.info,  Node: Echo server with anonymous authentication,  Next: DTLS echo server with X.509 authentication,  Prev: Echo server with SRP authentication,  Up: Server examples

7.2.4 Echo server with anonymous authentication
-----------------------------------------------

This example server supports anonymous authentication, and could be used
to serve the example client for anonymous authentication.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>

/* This is a sample TLS 1.0 echo server, for anonymous authentication only.
 */


#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}
#define MAX_BUF 1024
#define PORT 5556               /* listen to 5556 port */

/* These are global */
static gnutls_dh_params_t dh_params;

static int generate_dh_params(void)
{
        unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
                                                        GNUTLS_SEC_PARAM_LEGACY);
        /* Generate Diffie-Hellman parameters - for use with DHE
         * kx algorithms. These should be discarded and regenerated
         * once a day, once a week or once a month. Depending on the
         * security requirements.
         */
        gnutls_dh_params_init(&dh_params);
        gnutls_dh_params_generate2(dh_params, bits);

        return 0;
}

int main(void)
{
        int err, listen_sd;
        int sd, ret;
        struct sockaddr_in sa_serv;
        struct sockaddr_in sa_cli;
        socklen_t client_len;
        char topbuf[512];
        gnutls_session_t session;
        gnutls_anon_server_credentials_t anoncred;
        char buffer[MAX_BUF + 1];
        int optval = 1;

        if (gnutls_check_version("3.1.4") == NULL) {
                fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
                exit(1);
        }

        /* for backwards compatibility with gnutls < 3.3.0 */
        gnutls_global_init();

        gnutls_anon_allocate_server_credentials(&anoncred);

        generate_dh_params();

        gnutls_anon_set_server_dh_params(anoncred, dh_params);

        /* Socket operations
         */
        listen_sd = socket(AF_INET, SOCK_STREAM, 0);
        SOCKET_ERR(listen_sd, "socket");

        memset(&sa_serv, '\0', sizeof(sa_serv));
        sa_serv.sin_family = AF_INET;
        sa_serv.sin_addr.s_addr = INADDR_ANY;
        sa_serv.sin_port = htons(PORT); /* Server Port number */

        setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
                   sizeof(int));

        err =
            bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv));
        SOCKET_ERR(err, "bind");
        err = listen(listen_sd, 1024);
        SOCKET_ERR(err, "listen");

        printf("Server ready. Listening to port '%d'.\n\n", PORT);

        client_len = sizeof(sa_cli);
        for (;;) {
                gnutls_init(&session, GNUTLS_SERVER);
                gnutls_priority_set_direct(session,
                                           "NORMAL::+ANON-ECDH:+ANON-DH",
                                           NULL);
                gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);

                sd = accept(listen_sd, (struct sockaddr *) &sa_cli,
                            &client_len);

                printf("- connection from %s, port %d\n",
                       inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf,
                                 sizeof(topbuf)), ntohs(sa_cli.sin_port));

                gnutls_transport_set_int(session, sd);

                do {
                        ret = gnutls_handshake(session);
                }
                while (ret < 0 && gnutls_error_is_fatal(ret) == 0);

                if (ret < 0) {
                        close(sd);
                        gnutls_deinit(session);
                        fprintf(stderr,
                                "*** Handshake has failed (%s)\n\n",
                                gnutls_strerror(ret));
                        continue;
                }
                printf("- Handshake was completed\n");

                /* see the Getting peer's information example */
                /* print_info(session); */

                for (;;) {
                        ret = gnutls_record_recv(session, buffer, MAX_BUF);

                        if (ret == 0) {
                                printf
                                    ("\n- Peer has closed the GnuTLS connection\n");
                                break;
                        } else if (ret < 0
                                   && gnutls_error_is_fatal(ret) == 0) {
                                fprintf(stderr, "*** Warning: %s\n",
                                        gnutls_strerror(ret));
                        } else if (ret < 0) {
                                fprintf(stderr, "\n*** Received corrupted "
                                        "data(%d). Closing the connection.\n\n",
                                        ret);
                                break;
                        } else if (ret > 0) {
                                /* echo data back to the client
                                 */
                                gnutls_record_send(session, buffer, ret);
                        }
                }
                printf("\n");
                /* do not wait for the peer to close the connection.
                 */
                gnutls_bye(session, GNUTLS_SHUT_WR);

                close(sd);
                gnutls_deinit(session);

        }
        close(listen_sd);

        gnutls_anon_free_server_credentials(anoncred);

        gnutls_global_deinit();

        return 0;

}


File: gnutls.info,  Node: DTLS echo server with X.509 authentication,  Prev: Echo server with anonymous authentication,  Up: Server examples

7.2.5 DTLS echo server with X.509 authentication
------------------------------------------------

This example is a very simple echo server using Datagram TLS and X.509
authentication.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>

#define KEYFILE "key.pem"
#define CERTFILE "cert.pem"
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define CRLFILE "crl.pem"

/* This is a sample DTLS echo server, using X.509 authentication.
 * Note that error checking is minimal to simplify the example.
 */

#define MAX_BUFFER 1024
#define PORT 5557

typedef struct {
        gnutls_session_t session;
        int fd;
        struct sockaddr *cli_addr;
        socklen_t cli_addr_size;
} priv_data_st;

static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms);
static ssize_t push_func(gnutls_transport_ptr_t p, const void *data,
                         size_t size);
static ssize_t pull_func(gnutls_transport_ptr_t p, void *data,
                         size_t size);
static const char *human_addr(const struct sockaddr *sa, socklen_t salen,
                              char *buf, size_t buflen);
static int wait_for_connection(int fd);
static int generate_dh_params(void);

/* Use global credentials and parameters to simplify
 * the example. */
static gnutls_certificate_credentials_t x509_cred;
static gnutls_priority_t priority_cache;
static gnutls_dh_params_t dh_params;

int main(void)
{
        int listen_sd;
        int sock, ret;
        struct sockaddr_in sa_serv;
        struct sockaddr_in cli_addr;
        socklen_t cli_addr_size;
        gnutls_session_t session;
        char buffer[MAX_BUFFER];
        priv_data_st priv;
        gnutls_datum_t cookie_key;
        gnutls_dtls_prestate_st prestate;
        int mtu = 1400;
        unsigned char sequence[8];

        /* this must be called once in the program
         */
        gnutls_global_init();

        gnutls_certificate_allocate_credentials(&x509_cred);
        gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE,
                                               GNUTLS_X509_FMT_PEM);

        gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE,
                                             GNUTLS_X509_FMT_PEM);

        ret =
            gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE,
                                                 KEYFILE,
                                                 GNUTLS_X509_FMT_PEM);
        if (ret < 0) {
                printf("No certificate or key were found\n");
                exit(1);
        }

        generate_dh_params();

        gnutls_certificate_set_dh_params(x509_cred, dh_params);

        gnutls_priority_init(&priority_cache,
                             "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE",
                             NULL);

        gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE);

        /* Socket operations
         */
        listen_sd = socket(AF_INET, SOCK_DGRAM, 0);

        memset(&sa_serv, '\0', sizeof(sa_serv));
        sa_serv.sin_family = AF_INET;
        sa_serv.sin_addr.s_addr = INADDR_ANY;
        sa_serv.sin_port = htons(PORT);

        {                       /* DTLS requires the IP don't fragment (DF) bit to be set */
#if defined(IP_DONTFRAG)
                int optval = 1;
                setsockopt(listen_sd, IPPROTO_IP, IP_DONTFRAG,
                           (const void *) &optval, sizeof(optval));
#elif defined(IP_MTU_DISCOVER)
                int optval = IP_PMTUDISC_DO;
                setsockopt(listen_sd, IPPROTO_IP, IP_MTU_DISCOVER,
                           (const void *) &optval, sizeof(optval));
#endif
        }

        bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv));

        printf("UDP server ready. Listening to port '%d'.\n\n", PORT);

        for (;;) {
                printf("Waiting for connection...\n");
                sock = wait_for_connection(listen_sd);
                if (sock < 0)
                        continue;

                cli_addr_size = sizeof(cli_addr);
                ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK,
                               (struct sockaddr *) &cli_addr,
                               &cli_addr_size);
                if (ret > 0) {
                        memset(&prestate, 0, sizeof(prestate));
                        ret =
                            gnutls_dtls_cookie_verify(&cookie_key,
                                                      &cli_addr,
                                                      sizeof(cli_addr),
                                                      buffer, ret,
                                                      &prestate);
                        if (ret < 0) {  /* cookie not valid */
                                priv_data_st s;

                                memset(&s, 0, sizeof(s));
                                s.fd = sock;
                                s.cli_addr = (void *) &cli_addr;
                                s.cli_addr_size = sizeof(cli_addr);

                                printf
                                    ("Sending hello verify request to %s\n",
                                     human_addr((struct sockaddr *)
                                                &cli_addr,
                                                sizeof(cli_addr), buffer,
                                                sizeof(buffer)));

                                gnutls_dtls_cookie_send(&cookie_key,
                                                        &cli_addr,
                                                        sizeof(cli_addr),
                                                        &prestate,
                                                        (gnutls_transport_ptr_t)
                                                        & s, push_func);

                                /* discard peeked data */
                                recvfrom(sock, buffer, sizeof(buffer), 0,
                                         (struct sockaddr *) &cli_addr,
                                         &cli_addr_size);
                                usleep(100);
                                continue;
                        }
                        printf("Accepted connection from %s\n",
                               human_addr((struct sockaddr *)
                                          &cli_addr, sizeof(cli_addr),
                                          buffer, sizeof(buffer)));
                } else
                        continue;

                gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
                gnutls_priority_set(session, priority_cache);
                gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
                                       x509_cred);

                gnutls_dtls_prestate_set(session, &prestate);
                gnutls_dtls_set_mtu(session, mtu);

                priv.session = session;
                priv.fd = sock;
                priv.cli_addr = (struct sockaddr *) &cli_addr;
                priv.cli_addr_size = sizeof(cli_addr);

                gnutls_transport_set_ptr(session, &priv);
                gnutls_transport_set_push_function(session, push_func);
                gnutls_transport_set_pull_function(session, pull_func);
                gnutls_transport_set_pull_timeout_function(session,
                                                           pull_timeout_func);

                do {
                        ret = gnutls_handshake(session);
                }
                while (ret == GNUTLS_E_INTERRUPTED
                       || ret == GNUTLS_E_AGAIN);
                /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET.
                 * In that case the MTU should be adjusted.
                 */

                if (ret < 0) {
                        fprintf(stderr, "Error in handshake(): %s\n",
                                gnutls_strerror(ret));
                        gnutls_deinit(session);
                        continue;
                }

                printf("- Handshake was completed\n");

                for (;;) {
                        do {
                                ret =
                                    gnutls_record_recv_seq(session, buffer,
                                                           MAX_BUFFER,
                                                           sequence);
                        }
                        while (ret == GNUTLS_E_AGAIN
                               || ret == GNUTLS_E_INTERRUPTED);

                        if (ret < 0 && gnutls_error_is_fatal(ret) == 0) {
                                fprintf(stderr, "*** Warning: %s\n",
                                        gnutls_strerror(ret));
                                continue;
                        } else if (ret < 0) {
                                fprintf(stderr, "Error in recv(): %s\n",
                                        gnutls_strerror(ret));
                                break;
                        }

                        if (ret == 0) {
                                printf("EOF\n\n");
                                break;
                        }

                        buffer[ret] = 0;
                        printf
                            ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n",
                             sequence[0], sequence[1], sequence[2],
                             sequence[3], sequence[4], sequence[5],
                             sequence[6], sequence[7], buffer);

                        /* reply back */
                        ret = gnutls_record_send(session, buffer, ret);
                        if (ret < 0) {
                                fprintf(stderr, "Error in send(): %s\n",
                                        gnutls_strerror(ret));
                                break;
                        }
                }

                gnutls_bye(session, GNUTLS_SHUT_WR);
                gnutls_deinit(session);

        }
        close(listen_sd);

        gnutls_certificate_free_credentials(x509_cred);
        gnutls_priority_deinit(priority_cache);

        gnutls_global_deinit();

        return 0;

}

static int wait_for_connection(int fd)
{
        fd_set rd, wr;
        int n;

        FD_ZERO(&rd);
        FD_ZERO(&wr);

        FD_SET(fd, &rd);

        /* waiting part */
        n = select(fd + 1, &rd, &wr, NULL, NULL);
        if (n == -1 && errno == EINTR)
                return -1;
        if (n < 0) {
                perror("select()");
                exit(1);
        }

        return fd;
}

/* Wait for data to be received within a timeout period in milliseconds
 */
static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms)
{
        fd_set rfds;
        struct timeval tv;
        priv_data_st *priv = ptr;
        struct sockaddr_in cli_addr;
        socklen_t cli_addr_size;
        int ret;
        char c;

        FD_ZERO(&rfds);
        FD_SET(priv->fd, &rfds);

        tv.tv_sec = 0;
        tv.tv_usec = ms * 1000;

        while (tv.tv_usec >= 1000000) {
                tv.tv_usec -= 1000000;
                tv.tv_sec++;
        }

        ret = select(priv->fd + 1, &rfds, NULL, NULL, &tv);

        if (ret <= 0)
                return ret;

        /* only report ok if the next message is from the peer we expect
         * from
         */
        cli_addr_size = sizeof(cli_addr);
        ret =
            recvfrom(priv->fd, &c, 1, MSG_PEEK,
                     (struct sockaddr *) &cli_addr, &cli_addr_size);
        if (ret > 0) {
                if (cli_addr_size == priv->cli_addr_size
                    && memcmp(&cli_addr, priv->cli_addr,
                              sizeof(cli_addr)) == 0)
                        return 1;
        }

        return 0;
}

static ssize_t
push_func(gnutls_transport_ptr_t p, const void *data, size_t size)
{
        priv_data_st *priv = p;

        return sendto(priv->fd, data, size, 0, priv->cli_addr,
                      priv->cli_addr_size);
}

static ssize_t pull_func(gnutls_transport_ptr_t p, void *data, size_t size)
{
        priv_data_st *priv = p;
        struct sockaddr_in cli_addr;
        socklen_t cli_addr_size;
        char buffer[64];
        int ret;

        cli_addr_size = sizeof(cli_addr);
        ret =
            recvfrom(priv->fd, data, size, 0,
                     (struct sockaddr *) &cli_addr, &cli_addr_size);
        if (ret == -1)
                return ret;

        if (cli_addr_size == priv->cli_addr_size
            && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0)
                return ret;

        printf("Denied connection from %s\n",
               human_addr((struct sockaddr *)
                          &cli_addr, sizeof(cli_addr), buffer,
                          sizeof(buffer)));

        gnutls_transport_set_errno(priv->session, EAGAIN);
        return -1;
}

static const char *human_addr(const struct sockaddr *sa, socklen_t salen,
                              char *buf, size_t buflen)
{
        const char *save_buf = buf;
        size_t l;

        if (!buf || !buflen)
                return NULL;

        *buf = '\0';

        switch (sa->sa_family) {
#if HAVE_IPV6
        case AF_INET6:
                snprintf(buf, buflen, "IPv6 ");
                break;
#endif

        case AF_INET:
                snprintf(buf, buflen, "IPv4 ");
                break;
        }

        l = strlen(buf);
        buf += l;
        buflen -= l;

        if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) !=
            0)
                return NULL;

        l = strlen(buf);
        buf += l;
        buflen -= l;

        strncat(buf, " port ", buflen);

        l = strlen(buf);
        buf += l;
        buflen -= l;

        if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) !=
            0)
                return NULL;

        return save_buf;
}

static int generate_dh_params(void)
{
        int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
                                               GNUTLS_SEC_PARAM_LEGACY);

        /* Generate Diffie-Hellman parameters - for use with DHE
         * kx algorithms. When short bit length is used, it might
         * be wise to regenerate parameters often.
         */
        gnutls_dh_params_init(&dh_params);
        gnutls_dh_params_generate2(dh_params, bits);

        return 0;
}


File: gnutls.info,  Node: OCSP example,  Next: Miscellaneous examples,  Prev: Server examples,  Up: GnuTLS application examples

7.3 OCSP example
================

Generate OCSP request
---------------------

A small tool to generate OCSP requests.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <gnutls/ocsp.h>
#ifndef NO_LIBCURL
#include <curl/curl.h>
#endif
#include "read-file.h"

size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp);
static gnutls_x509_crt_t load_cert(const char *cert_file);
static void _response_info(const gnutls_datum_t * data);
static void
_generate_request(gnutls_datum_t * rdata, gnutls_x509_crt_t cert,
                  gnutls_x509_crt_t issuer, gnutls_datum_t *nonce);
static int
_verify_response(gnutls_datum_t * data, gnutls_x509_crt_t cert,
                 gnutls_x509_crt_t signer, gnutls_datum_t *nonce);

/* This program queries an OCSP server.
   It expects three files. argv[1] containing the certificate to
   be checked, argv[2] holding the issuer for this certificate,
   and argv[3] holding a trusted certificate to verify OCSP's response.
   argv[4] is optional and should hold the server host name.

   For simplicity the libcurl library is used.
 */

int main(int argc, char *argv[])
{
        gnutls_datum_t ud, tmp;
        int ret;
        gnutls_datum_t req;
        gnutls_x509_crt_t cert, issuer, signer;
#ifndef NO_LIBCURL
        CURL *handle;
        struct curl_slist *headers = NULL;
#endif
        int v, seq;
        const char *cert_file = argv[1];
        const char *issuer_file = argv[2];
        const char *signer_file = argv[3];
        char *hostname = NULL;
        unsigned char noncebuf[23];
        gnutls_datum_t nonce = { noncebuf, sizeof(noncebuf) };

        gnutls_global_init();

        if (argc > 4)
                hostname = argv[4];

        ret = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
        if (ret < 0)
                exit(1);

        cert = load_cert(cert_file);
        issuer = load_cert(issuer_file);
        signer = load_cert(signer_file);

        if (hostname == NULL) {

                for (seq = 0;; seq++) {
                        ret =
                            gnutls_x509_crt_get_authority_info_access(cert,
                                                                      seq,
                                                                      GNUTLS_IA_OCSP_URI,
                                                                      &tmp,
                                                                      NULL);
                        if (ret == GNUTLS_E_UNKNOWN_ALGORITHM)
                                continue;
                        if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
                                fprintf(stderr,
                                        "No URI was found in the certificate.\n");
                                exit(1);
                        }
                        if (ret < 0) {
                                fprintf(stderr, "error: %s\n",
                                        gnutls_strerror(ret));
                                exit(1);
                        }

                        printf("CA issuers URI: %.*s\n", tmp.size,
                               tmp.data);

                        hostname = malloc(tmp.size + 1);
                        memcpy(hostname, tmp.data, tmp.size);
                        hostname[tmp.size] = 0;

                        gnutls_free(tmp.data);
                        break;
                }

        }

        /* Note that the OCSP servers hostname might be available
         * using gnutls_x509_crt_get_authority_info_access() in the issuer's
         * certificate */

        memset(&ud, 0, sizeof(ud));
        fprintf(stderr, "Connecting to %s\n", hostname);

        _generate_request(&req, cert, issuer, &nonce);

#ifndef NO_LIBCURL
        curl_global_init(CURL_GLOBAL_ALL);

        handle = curl_easy_init();
        if (handle == NULL)
                exit(1);

        headers =
            curl_slist_append(headers,
                              "Content-Type: application/ocsp-request");

        curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(handle, CURLOPT_POSTFIELDS, (void *) req.data);
        curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.size);
        curl_easy_setopt(handle, CURLOPT_URL, hostname);
        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, get_data);
        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &ud);

        ret = curl_easy_perform(handle);
        if (ret != 0) {
                fprintf(stderr, "curl[%d] error %d\n", __LINE__, ret);
                exit(1);
        }

        curl_easy_cleanup(handle);
#endif

        _response_info(&ud);

        v = _verify_response(&ud, cert, signer, &nonce);

        gnutls_x509_crt_deinit(cert);
        gnutls_x509_crt_deinit(issuer);
        gnutls_x509_crt_deinit(signer);
        gnutls_global_deinit();

        return v;
}

static void _response_info(const gnutls_datum_t * data)
{
        gnutls_ocsp_resp_t resp;
        int ret;
        gnutls_datum buf;

        ret = gnutls_ocsp_resp_init(&resp);
        if (ret < 0)
                exit(1);

        ret = gnutls_ocsp_resp_import(resp, data);
        if (ret < 0)
                exit(1);

        ret = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
        if (ret != 0)
                exit(1);

        printf("%.*s", buf.size, buf.data);
        gnutls_free(buf.data);

        gnutls_ocsp_resp_deinit(resp);
}

static gnutls_x509_crt_t load_cert(const char *cert_file)
{
        gnutls_x509_crt_t crt;
        int ret;
        gnutls_datum_t data;
        size_t size;

        ret = gnutls_x509_crt_init(&crt);
        if (ret < 0)
                exit(1);

        data.data = (void *) read_binary_file(cert_file, &size);
        data.size = size;

        if (!data.data) {
                fprintf(stderr, "Cannot open file: %s\n", cert_file);
                exit(1);
        }

        ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM);
        free(data.data);
        if (ret < 0) {
                fprintf(stderr, "Cannot import certificate in %s: %s\n",
                        cert_file, gnutls_strerror(ret));
                exit(1);
        }

        return crt;
}

static void
_generate_request(gnutls_datum_t * rdata, gnutls_x509_crt_t cert,
                  gnutls_x509_crt_t issuer, gnutls_datum_t *nonce)
{
        gnutls_ocsp_req_t req;
        int ret;

        ret = gnutls_ocsp_req_init(&req);
        if (ret < 0)
                exit(1);

        ret = gnutls_ocsp_req_add_cert(req, GNUTLS_DIG_SHA1, issuer, cert);
        if (ret < 0)
                exit(1);


        ret = gnutls_ocsp_req_set_nonce(req, 0, nonce);
        if (ret < 0)
                exit(1);

        ret = gnutls_ocsp_req_export(req, rdata);
        if (ret != 0)
                exit(1);

        gnutls_ocsp_req_deinit(req);

        return;
}

static int
_verify_response(gnutls_datum_t * data, gnutls_x509_crt_t cert,
                 gnutls_x509_crt_t signer, gnutls_datum_t *nonce)
{
        gnutls_ocsp_resp_t resp;
        int ret;
        unsigned verify;
        gnutls_datum_t rnonce;

        ret = gnutls_ocsp_resp_init(&resp);
        if (ret < 0)
                exit(1);

        ret = gnutls_ocsp_resp_import(resp, data);
        if (ret < 0)
                exit(1);

        ret = gnutls_ocsp_resp_check_crt(resp, 0, cert);
        if (ret < 0)
                exit(1);

	ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce);
	if (ret < 0)
		exit(1);

	if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data,
		nonce->size) != 0) {
		exit(1);
	}

        ret = gnutls_ocsp_resp_verify_direct(resp, signer, &verify, 0);
        if (ret < 0)
                exit(1);

        printf("Verifying OCSP Response: ");
        if (verify == 0)
                printf("Verification success!\n");
        else
                printf("Verification error!\n");

        if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
                printf("Signer cert not found\n");

        if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
                printf("Signer cert keyusage error\n");

        if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
                printf("Signer cert is not trusted\n");

        if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
                printf("Insecure algorithm\n");

        if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
                printf("Signature failure\n");

        if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
                printf("Signer cert not yet activated\n");

        if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
                printf("Signer cert expired\n");

        gnutls_free(rnonce.data);
        gnutls_ocsp_resp_deinit(resp);

        return verify;
}

size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
        gnutls_datum_t *ud = userp;

        size *= nmemb;

        ud->data = realloc(ud->data, size + ud->size);
        if (ud->data == NULL) {
                fprintf(stderr, "Not enough memory for the request\n");
                exit(1);
        }

        memcpy(&ud->data[ud->size], buffer, size);
        ud->size += size;

        return size;
}


File: gnutls.info,  Node: Miscellaneous examples,  Prev: OCSP example,  Up: GnuTLS application examples

7.4 Miscellaneous examples
==========================

* Menu:

* Checking for an alert::
* X.509 certificate parsing example::
* Listing the ciphersuites in a priority string::
* PKCS12 structure generation example::


File: gnutls.info,  Node: Checking for an alert,  Next: X.509 certificate parsing example,  Up: Miscellaneous examples

7.4.1 Checking for an alert
---------------------------

This is a function that checks if an alert has been received in the
current session.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>

#include "examples.h"

/* This function will check whether the given return code from
 * a gnutls function (recv/send), is an alert, and will print
 * that alert.
 */
void check_alert(gnutls_session_t session, int ret)
{
        int last_alert;

        if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
            || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
                last_alert = gnutls_alert_get(session);

                /* The check for renegotiation is only useful if we are
                 * a server, and we had requested a rehandshake.
                 */
                if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
                    ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
                        printf("* Received NO_RENEGOTIATION alert. "
                               "Client Does not support renegotiation.\n");
                else
                        printf("* Received alert '%d': %s.\n", last_alert,
                               gnutls_alert_get_name(last_alert));
        }
}


File: gnutls.info,  Node: X.509 certificate parsing example,  Next: Listing the ciphersuites in a priority string,  Prev: Checking for an alert,  Up: Miscellaneous examples

7.4.2 X.509 certificate parsing example
---------------------------------------

To demonstrate the X.509 parsing capabilities an example program is
listed below.  That program reads the peer's certificate, and prints
information about it.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>

#include "examples.h"

static const char *bin2hex(const void *bin, size_t bin_size)
{
        static char printable[110];
        const unsigned char *_bin = bin;
        char *print;
        size_t i;

        if (bin_size > 50)
                bin_size = 50;

        print = printable;
        for (i = 0; i < bin_size; i++) {
                sprintf(print, "%.2x ", _bin[i]);
                print += 2;
        }

        return printable;
}

/* This function will print information about this session's peer
 * certificate.
 */
void print_x509_certificate_info(gnutls_session_t session)
{
        char serial[40];
        char dn[256];
        size_t size;
        unsigned int algo, bits;
        time_t expiration_time, activation_time;
        const gnutls_datum_t *cert_list;
        unsigned int cert_list_size = 0;
        gnutls_x509_crt_t cert;
        gnutls_datum_t cinfo;

        /* This function only works for X.509 certificates.
         */
        if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
                return;

        cert_list = gnutls_certificate_get_peers(session, &cert_list_size);

        printf("Peer provided %d certificates.\n", cert_list_size);

        if (cert_list_size > 0) {
                int ret;

                /* we only print information about the first certificate.
                 */
                gnutls_x509_crt_init(&cert);

                gnutls_x509_crt_import(cert, &cert_list[0],
                                       GNUTLS_X509_FMT_DER);

                printf("Certificate info:\n");

                /* This is the preferred way of printing short information about
                   a certificate. */

                ret =
                    gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE,
                                          &cinfo);
                if (ret == 0) {
                        printf("\t%s\n", cinfo.data);
                        gnutls_free(cinfo.data);
                }

                /* If you want to extract fields manually for some other reason,
                   below are popular example calls. */

                expiration_time =
                    gnutls_x509_crt_get_expiration_time(cert);
                activation_time =
                    gnutls_x509_crt_get_activation_time(cert);

                printf("\tCertificate is valid since: %s",
                       ctime(&activation_time));
                printf("\tCertificate expires: %s",
                       ctime(&expiration_time));

                /* Print the serial number of the certificate.
                 */
                size = sizeof(serial);
                gnutls_x509_crt_get_serial(cert, serial, &size);

                printf("\tCertificate serial number: %s\n",
                       bin2hex(serial, size));

                /* Extract some of the public key algorithm's parameters
                 */
                algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);

                printf("Certificate public key: %s",
                       gnutls_pk_algorithm_get_name(algo));

                /* Print the version of the X.509
                 * certificate.
                 */
                printf("\tCertificate version: #%d\n",
                       gnutls_x509_crt_get_version(cert));

                size = sizeof(dn);
                gnutls_x509_crt_get_dn(cert, dn, &size);
                printf("\tDN: %s\n", dn);

                size = sizeof(dn);
                gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
                printf("\tIssuer's DN: %s\n", dn);

                gnutls_x509_crt_deinit(cert);

        }
}


File: gnutls.info,  Node: Listing the ciphersuites in a priority string,  Next: PKCS12 structure generation example,  Prev: X.509 certificate parsing example,  Up: Miscellaneous examples

7.4.3 Listing the ciphersuites in a priority string
---------------------------------------------------

This is a small program to list the enabled ciphersuites by a priority
string.

/* This example code is placed in the public domain. */

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>

static void print_cipher_suite_list(const char *priorities)
{
        size_t i;
        int ret;
        unsigned int idx;
        const char *name;
        const char *err;
        unsigned char id[2];
        gnutls_protocol_t version;
        gnutls_priority_t pcache;

        if (priorities != NULL) {
                printf("Cipher suites for %s\n", priorities);

                ret = gnutls_priority_init(&pcache, priorities, &err);
                if (ret < 0) {
                        fprintf(stderr, "Syntax error at: %s\n", err);
                        exit(1);
                }

                for (i = 0;; i++) {
                        ret =
                            gnutls_priority_get_cipher_suite_index(pcache,
                                                                   i,
                                                                   &idx);
                        if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
                                break;
                        if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE)
                                continue;

                        name =
                            gnutls_cipher_suite_info(idx, id, NULL, NULL,
                                                     NULL, &version);

                        if (name != NULL)
                                printf("%-50s\t0x%02x, 0x%02x\t%s\n",
                                       name, (unsigned char) id[0],
                                       (unsigned char) id[1],
                                       gnutls_protocol_get_name(version));
                }

                return;
        }
}

int main(int argc, char **argv)
{
        if (argc > 1)
                print_cipher_suite_list(argv[1]);
        return 0;
}


File: gnutls.info,  Node: PKCS12 structure generation example,  Prev: Listing the ciphersuites in a priority string,  Up: Miscellaneous examples

7.4.4 PKCS #12 structure generation example
-------------------------------------------

This small program demonstrates the usage of the PKCS #12 API, by
generating such a structure.

/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <gnutls/gnutls.h>
#include <gnutls/pkcs12.h>

#include "examples.h"

#define OUTFILE "out.p12"

/* This function will write a pkcs12 structure into a file.
 * cert: is a DER encoded certificate
 * pkcs8_key: is a PKCS #8 encrypted key (note that this must be
 *  encrypted using a PKCS #12 cipher, or some browsers will crash)
 * password: is the password used to encrypt the PKCS #12 packet.
 */
int
write_pkcs12(const gnutls_datum_t * cert,
             const gnutls_datum_t * pkcs8_key, const char *password)
{
        gnutls_pkcs12_t pkcs12;
        int ret, bag_index;
        gnutls_pkcs12_bag_t bag, key_bag;
        char pkcs12_struct[10 * 1024];
        size_t pkcs12_struct_size;
        FILE *fd;

        /* A good idea might be to use gnutls_x509_privkey_get_key_id()
         * to obtain a unique ID.
         */
        gnutls_datum_t key_id = { (void *) "\x00\x00\x07", 3 };

        gnutls_global_init();

        /* Firstly we create two helper bags, which hold the certificate,
         * and the (encrypted) key.
         */

        gnutls_pkcs12_bag_init(&bag);
        gnutls_pkcs12_bag_init(&key_bag);

        ret =
            gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CERTIFICATE, cert);
        if (ret < 0) {
                fprintf(stderr, "ret: %s\n", gnutls_strerror(ret));
                return 1;
        }

        /* ret now holds the bag's index.
         */
        bag_index = ret;

        /* Associate a friendly name with the given certificate. Used
         * by browsers.
         */
        gnutls_pkcs12_bag_set_friendly_name(bag, bag_index, "My name");

        /* Associate the certificate with the key using a unique key
         * ID.
         */
        gnutls_pkcs12_bag_set_key_id(bag, bag_index, &key_id);

        /* use weak encryption for the certificate.
         */
        gnutls_pkcs12_bag_encrypt(bag, password,
                                  GNUTLS_PKCS_USE_PKCS12_RC2_40);

        /* Now the key.
         */

        ret = gnutls_pkcs12_bag_set_data(key_bag,
                                         GNUTLS_BAG_PKCS8_ENCRYPTED_KEY,
                                         pkcs8_key);
        if (ret < 0) {
                fprintf(stderr, "ret: %s\n", gnutls_strerror(ret));
                return 1;
        }

        /* Note that since the PKCS #8 key is already encrypted we don't
         * bother encrypting that bag.
         */
        bag_index = ret;

        gnutls_pkcs12_bag_set_friendly_name(key_bag, bag_index, "My name");

        gnutls_pkcs12_bag_set_key_id(key_bag, bag_index, &key_id);


        /* The bags were filled. Now create the PKCS #12 structure.
         */
        gnutls_pkcs12_init(&pkcs12);

        /* Insert the two bags in the PKCS #12 structure.
         */

        gnutls_pkcs12_set_bag(pkcs12, bag);
        gnutls_pkcs12_set_bag(pkcs12, key_bag);


        /* Generate a message authentication code for the PKCS #12
         * structure.
         */
        gnutls_pkcs12_generate_mac(pkcs12, password);

        pkcs12_struct_size = sizeof(pkcs12_struct);
        ret =
            gnutls_pkcs12_export(pkcs12, GNUTLS_X509_FMT_DER,
                                 pkcs12_struct, &pkcs12_struct_size);
        if (ret < 0) {
                fprintf(stderr, "ret: %s\n", gnutls_strerror(ret));
                return 1;
        }

        fd = fopen(OUTFILE, "w");
        if (fd == NULL) {
                fprintf(stderr, "cannot open file\n");
                return 1;
        }
        fwrite(pkcs12_struct, 1, pkcs12_struct_size, fd);
        fclose(fd);

        gnutls_pkcs12_bag_deinit(bag);
        gnutls_pkcs12_bag_deinit(key_bag);
        gnutls_pkcs12_deinit(pkcs12);

        return 0;
}


File: gnutls.info,  Node: Using GnuTLS as a cryptographic library,  Next: Other included programs,  Prev: GnuTLS application examples,  Up: Top

8 Using GnuTLS as a cryptographic library
*****************************************

GnuTLS is not a low-level cryptographic library, i.e., it does not
provide access to basic cryptographic primitives.  However it abstracts
the internal cryptographic back-end (see *note Cryptographic Backend::),
providing symmetric crypto, hash and HMAC algorithms, as well access to
the random number generation.  For a low-level crypto API the usage of
nettle (1) library is recommended.

* Menu:

* Symmetric algorithms::
* Public key algorithms::
* Hash and HMAC functions::
* Random number generation::

   ---------- Footnotes ----------

   (1) See <http://www.lysator.liu.se/~nisse/nettle/>.


File: gnutls.info,  Node: Symmetric algorithms,  Next: Public key algorithms,  Up: Using GnuTLS as a cryptographic library

8.1 Symmetric algorithms
========================

The available functions to access symmetric crypto algorithms operations
are shown below.  The supported algorithms are the algorithms required
by the TLS protocol.  They are listed in *note Table 3.1: tab:ciphers.

'INT *note gnutls_cipher_init:: (gnutls_cipher_hd_t * HANDLE, gnutls_cipher_algorithm_t CIPHER, const gnutls_datum_t * KEY, const gnutls_datum_t * IV)'
'INT *note gnutls_cipher_encrypt2:: (gnutls_cipher_hd_t HANDLE, const void * TEXT, size_t TEXTLEN, void * CIPHERTEXT, size_t CIPHERTEXTLEN)'
'INT *note gnutls_cipher_decrypt2:: (gnutls_cipher_hd_t HANDLE, const void * CIPHERTEXT, size_t CIPHERTEXTLEN, void * TEXT, size_t TEXTLEN)'
'VOID *note gnutls_cipher_set_iv:: (gnutls_cipher_hd_t HANDLE, void * IV, size_t IVLEN)'
'VOID *note gnutls_cipher_deinit:: (gnutls_cipher_hd_t HANDLE)'

In order to support authenticated encryption with associated data (AEAD)
algorithms the following functions are provided to set the associated
data and retrieve the authentication tag.

'INT *note gnutls_cipher_add_auth:: (gnutls_cipher_hd_t HANDLE, const void * TEXT, size_t TEXT_SIZE)'
'INT *note gnutls_cipher_tag:: (gnutls_cipher_hd_t HANDLE, void * TAG, size_t TAG_SIZE)'


File: gnutls.info,  Node: Public key algorithms,  Next: Hash and HMAC functions,  Prev: Symmetric algorithms,  Up: Using GnuTLS as a cryptographic library

8.2 Public key algorithms
=========================

Public key cryptography algorithms such as RSA, DSA and ECDSA, can be
accessed using the abstract key API in *note Abstract key types::.  This
is a high level API with the advantage of transparently handling keys in
memory and keys present in smart cards.


File: gnutls.info,  Node: Hash and HMAC functions,  Next: Random number generation,  Prev: Public key algorithms,  Up: Using GnuTLS as a cryptographic library

8.3 Hash and HMAC functions
===========================

The available operations to access hash functions and hash-MAC (HMAC)
algorithms are shown below.  HMAC algorithms provided keyed hash
functionality.  They supported HMAC algorithms are listed in *note Table
3.2: tab:macs.

'INT *note gnutls_hmac_init:: (gnutls_hmac_hd_t * DIG, gnutls_mac_algorithm_t ALGORITHM, const void * KEY, size_t KEYLEN)'
'INT *note gnutls_hmac:: (gnutls_hmac_hd_t HANDLE, const void * TEXT, size_t TEXTLEN)'
'VOID *note gnutls_hmac_output:: (gnutls_hmac_hd_t HANDLE, void * DIGEST)'
'VOID *note gnutls_hmac_deinit:: (gnutls_hmac_hd_t HANDLE, void * DIGEST)'
'INT *note gnutls_hmac_get_len:: (gnutls_mac_algorithm_t ALGORITHM)'
'INT *note gnutls_hmac_fast:: (gnutls_mac_algorithm_t ALGORITHM, const void * KEY, size_t KEYLEN, const void * TEXT, size_t TEXTLEN, void * DIGEST)'

The available functions to access hash functions are shown below.  The
supported hash functions are the same as the HMAC algorithms.

'INT *note gnutls_hash_init:: (gnutls_hash_hd_t * DIG, gnutls_digest_algorithm_t ALGORITHM)'
'INT *note gnutls_hash:: (gnutls_hash_hd_t HANDLE, const void * TEXT, size_t TEXTLEN)'
'VOID *note gnutls_hash_output:: (gnutls_hash_hd_t HANDLE, void * DIGEST)'
'VOID *note gnutls_hash_deinit:: (gnutls_hash_hd_t HANDLE, void * DIGEST)'
'INT *note gnutls_hash_get_len:: (gnutls_digest_algorithm_t ALGORITHM)'
'INT *note gnutls_hash_fast:: (gnutls_digest_algorithm_t ALGORITHM, const void * TEXT, size_t TEXTLEN, void * DIGEST)'
'INT *note gnutls_fingerprint:: (gnutls_digest_algorithm_t ALGO, const gnutls_datum_t * DATA, void * RESULT, size_t * RESULT_SIZE)'


File: gnutls.info,  Node: Random number generation,  Prev: Hash and HMAC functions,  Up: Using GnuTLS as a cryptographic library

8.4 Random number generation
============================

Access to the random number generator is provided using the *note
gnutls_rnd:: function.  It allows obtaining random data of various
levels.

'GNUTLS_RND_NONCE'
     Non-predictable random number.  Fatal in parts of session if
     broken, i.e., vulnerable to statistical analysis.
'GNUTLS_RND_RANDOM'
     Pseudo-random cryptographic random number.  Fatal in session if
     broken.
'GNUTLS_RND_KEY'
     Fatal in many sessions if broken.

Figure 8.1: The random number levels.

 -- Function: int gnutls_rnd (gnutls_rnd_level_t LEVEL, void * DATA,
          size_t LEN)
     LEVEL: a security level

     DATA: place to store random bytes

     LEN: The requested size

     This function will generate random data and store it to output
     buffer.

     This function is thread-safe and also fork-safe.

     *Returns:* Zero on success, or a negative error code on error.

     *Since:* 2.12.0


File: gnutls.info,  Node: Other included programs,  Next: Internal architecture of GnuTLS,  Prev: Using GnuTLS as a cryptographic library,  Up: Top

9 Other included programs
*************************

Included with GnuTLS are also a few command line tools that let you use
the library for common tasks without writing an application.  The
applications are discussed in this chapter.

* Menu:

* gnutls-cli Invocation::          Invoking gnutls-cli
* gnutls-serv Invocation::         Invoking gnutls-serv
* gnutls-cli-debug Invocation::    Invoking gnutls-cli-debug


File: gnutls.info,  Node: gnutls-cli Invocation,  Next: gnutls-serv Invocation,  Up: Other included programs

9.1 Invoking gnutls-cli
=======================

Simple client program to set up a TLS connection to some other computer.
It sets up a TLS connection and forwards data from the standard input to
the secured socket and vice versa.

This section was generated by *AutoGen*, using the 'agtexi-cmd' template
and the option descriptions for the 'gnutls-cli' program.  This software
is released under the GNU General Public License, version 3 or later.

gnutls-cli help/usage ('--help')
--------------------------------

This is the automatically generated usage text for gnutls-cli.

The text printed is the same whether selected with the 'help' option
('--help') or the 'more-help' option ('--more-help').  'more-help' will
print the usage text by passing it through a pager program.  'more-help'
is disabled on platforms without a working 'fork(2)' function.  The
'PAGER' environment variable is used to select the program, defaulting
to 'more'.  Both will exit with a status code of 0.

     gnutls-cli - GnuTLS client
     Usage:  gnutls-cli [ -<flag> [<val>] | --<name>[{=| }<val>] ]... [hostname]

        -d, --debug=num            Enable debugging
                                     - it must be in the range:
                                       0 to 9999
        -V, --verbose              More verbose output
                                     - may appear multiple times
            --tofu                 Enable trust on first use authentication
                                     - disabled as '--no-tofu'
            --strict-tofu          Fail to connect if a known certificate has changed
                                     - disabled as '--no-strict-tofu'
            --dane                 Enable DANE certificate verification (DNSSEC)
                                     - disabled as '--no-dane'
            --local-dns            Use the local DNS server for DNSSEC resolving
                                     - disabled as '--no-local-dns'
            --ca-verification      Enable CA certificate verification
                                     - disabled as '--no-ca-verification'
                                     - enabled by default
            --ocsp                 Enable OCSP certificate verification
                                     - disabled as '--no-ocsp'
        -r, --resume               Establish a session and resume
        -e, --rehandshake          Establish a session and rehandshake
        -s, --starttls             Connect, establish a plain session and start TLS
            --app-proto=str        an alias for the 'starttls-proto' option
            --starttls-proto=str   The application protocol to be used to obtain the server's certificate
     (https, ftp, smtp, imap, ldap, xmpp)
                                     - prohibits the option 'starttls'
        -u, --udp                  Use DTLS (datagram TLS) over UDP
            --mtu=num              Set MTU for datagram TLS
                                     - it must be in the range:
                                       0 to 17000
            --crlf                 Send CR LF instead of LF
            --fastopen             Enable TCP Fast Open
            --x509fmtder           Use DER format for certificates to read from
        -f, --fingerprint          Send the openpgp fingerprint, instead of the key
            --print-cert           Print peer's certificate in PEM format
            --save-cert=str        Save the peer's certificate chain in the specified file in PEM format
            --save-ocsp=str        Save the peer's OCSP status response in the provided file
            --dh-bits=num          The minimum number of bits allowed for DH
            --priority=str         Priorities string
            --x509cafile=str       Certificate file or PKCS #11 URL to use
            --x509crlfile=file     CRL file to use
                                     - file must pre-exist
            --pgpkeyfile=file      PGP Key file to use
                                     - file must pre-exist
            --pgpkeyring=file      PGP Key ring file to use
                                     - file must pre-exist
            --pgpcertfile=file     PGP Public Key (certificate) file to use
                                     - requires the option 'pgpkeyfile'
                                     - file must pre-exist
            --x509keyfile=str      X.509 key file or PKCS #11 URL to use
            --x509certfile=str     X.509 Certificate file or PKCS #11 URL to use
                                     - requires the option 'x509keyfile'
            --pgpsubkey=str        PGP subkey to use (hex or auto)
            --srpusername=str      SRP username to use
            --srppasswd=str        SRP password to use
            --pskusername=str      PSK username to use
            --pskkey=str           PSK key (in hex) to use
        -p, --port=str             The port or service to connect to
            --insecure             Don't abort program if server certificate can't be validated
            --ranges               Use length-hiding padding to prevent traffic analysis
            --benchmark-ciphers    Benchmark individual ciphers
            --benchmark-tls-kx     Benchmark TLS key exchange methods
            --benchmark-tls-ciphers  Benchmark TLS ciphers
        -l, --list                 Print a list of the supported algorithms and modes
                                     - prohibits the option 'port'
            --priority-list        Print a list of the supported priority strings
            --noticket             Don't allow session tickets
            --srtp-profiles=str    Offer SRTP profiles
            --alpn=str             Application layer protocol
                                     - may appear multiple times
        -b, --heartbeat            Activate heartbeat support
            --recordsize=num       The maximum record size to advertize
                                     - it must be in the range:
                                       0 to 4096
            --disable-sni          Do not send a Server Name Indication (SNI)
            --disable-extensions   Disable all the TLS extensions
            --inline-commands      Inline commands of the form ^<cmd>^
            --inline-commands-prefix=str Change the default delimiter for inline commands.
            --provider=file        Specify the PKCS #11 provider library
                                     - file must pre-exist
            --fips140-mode         Reports the status of the FIPS140-2 mode in gnutls library
        -v, --version[=arg]        output version information and exit
        -h, --help                 display extended usage information and exit
        -!, --more-help            extended usage information passed thru pager

     Options are specified by doubled hyphens and their name or by a single
     hyphen and the flag character.
     Operands and options may be intermixed.  They will be reordered.

     Simple client program to set up a TLS connection to some other computer.  It
     sets up a TLS connection and forwards data from the standard input to the
     secured socket and vice versa.


debug option (-d)
-----------------

This is the "enable debugging" option.  This option takes a number
argument.  Specifies the debug level.

tofu option
-----------

This is the "enable trust on first use authentication" option.

This option has some usage constraints.  It:
   * can be disabled with -no-tofu.

This option will, in addition to certificate authentication, perform
authentication based on previously seen public keys, a model similar to
SSH authentication.  Note that when tofu is specified (PKI) and DANE
authentication will become advisory to assist the public key acceptance
process.

strict-tofu option
------------------

This is the "fail to connect if a known certificate has changed" option.

This option has some usage constraints.  It:
   * can be disabled with -no-strict-tofu.

This option will perform authentication as with option -tofu; however,
while -tofu asks whether to trust a changed public key, this option will
fail in case of public key changes.

dane option
-----------

This is the "enable dane certificate verification (dnssec)" option.

This option has some usage constraints.  It:
   * can be disabled with -no-dane.

This option will, in addition to certificate authentication using the
trusted CAs, verify the server certificates using on the DANE
information available via DNSSEC.

local-dns option
----------------

This is the "use the local dns server for dnssec resolving" option.

This option has some usage constraints.  It:
   * can be disabled with -no-local-dns.

This option will use the local DNS server for DNSSEC. This is disabled
by default due to many servers not allowing DNSSEC.

ca-verification option
----------------------

This is the "disable ca certificate verification" option.

This option has some usage constraints.  It:
   * can be disabled with -no-ca-verification.
   * It is enabled by default.

This option will disable CA certificate verification.  It is to be used
with the -dane or -tofu options.

ocsp option
-----------

This is the "enable ocsp certificate verification" option.

This option has some usage constraints.  It:
   * can be disabled with -no-ocsp.

This option will enable verification of the peer's certificate using
ocsp

resume option (-r)
------------------

This is the "establish a session and resume" option.  Connect, establish
a session, reconnect and resume.

rehandshake option (-e)
-----------------------

This is the "establish a session and rehandshake" option.  Connect,
establish a session and rehandshake immediately.

starttls option (-s)
--------------------

This is the "connect, establish a plain session and start tls" option.
The TLS session will be initiated when EOF or a SIGALRM is received.

app-proto option
----------------

This is an alias for the 'starttls-proto' option, *note the
starttls-proto option documentation: gnutls-cli starttls-proto.

starttls-proto option
---------------------

This is the "the application protocol to be used to obtain the server's
certificate (https, ftp, smtp, imap)" option.  This option takes a
string argument.

This option has some usage constraints.  It:
   * must not appear in combination with any of the following options:
     starttls.

Specify the application layer protocol for STARTTLS. If the protocol is
supported, gnutls-cli will proceed to the TLS negotiation.

dh-bits option
--------------

This is the "the minimum number of bits allowed for dh" option.  This
option takes a number argument.  This option sets the minimum number of
bits allowed for a Diffie-Hellman key exchange.  You may want to lower
the default value if the peer sends a weak prime and you get an
connection error with unacceptable prime.

priority option
---------------

This is the "priorities string" option.  This option takes a string
argument.  TLS algorithms and protocols to enable.  You can use
predefined sets of ciphersuites such as PERFORMANCE, NORMAL, PFS,
SECURE128, SECURE256.  The default is NORMAL.

Check the GnuTLS manual on section "Priority strings" for more
information on the allowed keywords

ranges option
-------------

This is the "use length-hiding padding to prevent traffic analysis"
option.  When possible (e.g., when using CBC ciphersuites), use
length-hiding padding to prevent traffic analysis.

list option (-l)
----------------

This is the "print a list of the supported algorithms and modes" option.

This option has some usage constraints.  It:
   * must not appear in combination with any of the following options:
     port.

Print a list of the supported algorithms and modes.  If a priority
string is given then only the enabled ciphersuites are shown.

alpn option
-----------

This is the "application layer protocol" option.  This option takes a
string argument.

This option has some usage constraints.  It:
   * may appear an unlimited number of times.

This option will set and enable the Application Layer Protocol
Negotiation (ALPN) in the TLS protocol.

disable-extensions option
-------------------------

This is the "disable all the tls extensions" option.  This option
disables all TLS extensions.  Deprecated option.  Use the priority
string.

inline-commands option
----------------------

This is the "inline commands of the form ^<cmd>^" option.  Enable inline
commands of the form ^<cmd>^.  The inline commands are expected to be in
a line by themselves.  The available commands are: resume and
renegotiate.

inline-commands-prefix option
-----------------------------

This is the "change the default delimiter for inline commands."  option.
This option takes a string argument.  Change the default delimiter (^)
used for inline commands.  The delimiter is expected to be a single
US-ASCII character (octets 0 - 127).  This option is only relevant if
inline commands are enabled via the inline-commands option

provider option
---------------

This is the "specify the pkcs #11 provider library" option.  This option
takes a file argument.  This will override the default options in
/etc/gnutls/pkcs11.conf

gnutls-cli exit status
----------------------

One of the following exit values will be returned:
'0 (EXIT_SUCCESS)'
     Successful program execution.
'1 (EXIT_FAILURE)'
     The operation failed or the command syntax was not valid.

gnutls-cli See Also
-------------------

gnutls-cli-debug(1), gnutls-serv(1)

gnutls-cli Examples
-------------------

Connecting using PSK authentication
-----------------------------------

To connect to a server using PSK authentication, you need to enable the
choice of PSK by using a cipher priority parameter such as in the
example below.
     $ ./gnutls-cli -p 5556 localhost --pskusername psk_identity \
         --pskkey 88f3824b3e5659f52d00e959bacab954b6540344 \
         --priority NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK
     Resolving 'localhost'...
     Connecting to '127.0.0.1:5556'...
     - PSK authentication.
     - Version: TLS1.1
     - Key Exchange: PSK
     - Cipher: AES-128-CBC
     - MAC: SHA1
     - Compression: NULL
     - Handshake was completed

     - Simple Client Mode:
By keeping the -pskusername parameter and removing the -pskkey
parameter, it will query only for the password during the handshake.

Listing ciphersuites in a priority string
-----------------------------------------

To list the ciphersuites in a priority string:
     $ ./gnutls-cli --priority SECURE192 -l
     Cipher suites for SECURE192
     TLS_ECDHE_ECDSA_AES_256_CBC_SHA384         0xc0, 0x24	TLS1.2
     TLS_ECDHE_ECDSA_AES_256_GCM_SHA384         0xc0, 0x2e	TLS1.2
     TLS_ECDHE_RSA_AES_256_GCM_SHA384           0xc0, 0x30	TLS1.2
     TLS_DHE_RSA_AES_256_CBC_SHA256             0x00, 0x6b	TLS1.2
     TLS_DHE_DSS_AES_256_CBC_SHA256             0x00, 0x6a	TLS1.2
     TLS_RSA_AES_256_CBC_SHA256                 0x00, 0x3d	TLS1.2

     Certificate types: CTYPE-X.509
     Protocols: VERS-TLS1.2, VERS-TLS1.1, VERS-TLS1.0, VERS-SSL3.0, VERS-DTLS1.0
     Compression: COMP-NULL
     Elliptic curves: CURVE-SECP384R1, CURVE-SECP521R1
     PK-signatures: SIGN-RSA-SHA384, SIGN-ECDSA-SHA384, SIGN-RSA-SHA512, SIGN-ECDSA-SHA512

Connecting using a PKCS #11 token
---------------------------------

To connect to a server using a certificate and a private key present in
a PKCS #11 token you need to substitute the PKCS 11 URLs in the
x509certfile and x509keyfile parameters.

Those can be found using "p11tool -list-tokens" and then listing all the
objects in the needed token, and using the appropriate.
     $ p11tool --list-tokens

     Token 0:
     URL: pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test
     Label: Test
     Manufacturer: EnterSafe
     Model: PKCS15
     Serial: 1234

     $ p11tool --login --list-certs "pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test"

     Object 0:
     URL: pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test;object=client;object-type=cert
     Type: X.509 Certificate
     Label: client
     ID: 2a:97:0d:58:d1:51:3c:23:07:ae:4e:0d:72:26:03:7d:99:06:02:6a

     $ export MYCERT="pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test;object=client;object-type=cert"
     $ export MYKEY="pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test;object=client;object-type=private"

     $ gnutls-cli www.example.com --x509keyfile $MYKEY --x509certfile MYCERT
Notice that the private key only differs from the certificate in the
object-type.


File: gnutls.info,  Node: gnutls-serv Invocation,  Next: gnutls-cli-debug Invocation,  Prev: gnutls-cli Invocation,  Up: Other included programs

9.2 Invoking gnutls-serv
========================

Server program that listens to incoming TLS connections.

This section was generated by *AutoGen*, using the 'agtexi-cmd' template
and the option descriptions for the 'gnutls-serv' program.  This
software is released under the GNU General Public License, version 3 or
later.

gnutls-serv help/usage ('--help')
---------------------------------

This is the automatically generated usage text for gnutls-serv.

The text printed is the same whether selected with the 'help' option
('--help') or the 'more-help' option ('--more-help').  'more-help' will
print the usage text by passing it through a pager program.  'more-help'
is disabled on platforms without a working 'fork(2)' function.  The
'PAGER' environment variable is used to select the program, defaulting
to 'more'.  Both will exit with a status code of 0.

     gnutls-serv - GnuTLS server
     Usage:  gnutls-serv [ -<flag> [<val>] | --<name>[{=| }<val>] ]...

        -d, --debug=num            Enable debugging
                                     - it must be in the range:
                                       0 to 9999
            --sni-hostname=str     Server's hostname for server name extension
            --sni-hostname-fatal   Send fatal alert on sni-hostname mismatch
            --noticket             Don't accept session tickets
        -g, --generate             Generate Diffie-Hellman parameters
        -q, --quiet                Suppress some messages
            --nodb                 Do not use a resumption database
            --http                 Act as an HTTP server
            --echo                 Act as an Echo server
        -u, --udp                  Use DTLS (datagram TLS) over UDP
            --mtu=num              Set MTU for datagram TLS
                                     - it must be in the range:
                                       0 to 17000
            --srtp-profiles=str    Offer SRTP profiles
        -a, --disable-client-cert  Do not request a client certificate
        -r, --require-client-cert  Require a client certificate
            --verify-client-cert   If a client certificate is sent then verify it.
        -b, --heartbeat            Activate heartbeat support
            --x509fmtder           Use DER format for certificates to read from
            --priority=str         Priorities string
            --dhparams=file        DH params file to use
                                     - file must pre-exist
            --x509cafile=str       Certificate file or PKCS #11 URL to use
            --x509crlfile=file     CRL file to use
                                     - file must pre-exist
            --pgpkeyfile=file      PGP Key file to use
                                     - file must pre-exist
            --pgpkeyring=file      PGP Key ring file to use
                                     - file must pre-exist
            --pgpcertfile=file     PGP Public Key (certificate) file to use
                                     - file must pre-exist
            --x509keyfile=str      X.509 key file or PKCS #11 URL to use
            --x509certfile=str     X.509 Certificate file or PKCS #11 URL to use
            --x509dsakeyfile=str   Alternative X.509 key file or PKCS #11 URL to use
            --x509dsacertfile=str  Alternative X.509 Certificate file or PKCS #11 URL to use
            --x509ecckeyfile=str   Alternative X.509 key file or PKCS #11 URL to use
            --x509ecccertfile=str  Alternative X.509 Certificate file or PKCS #11 URL to use
            --pgpsubkey=str        PGP subkey to use (hex or auto)
            --srppasswd=file       SRP password file to use
                                     - file must pre-exist
            --srppasswdconf=file   SRP password configuration file to use
                                     - file must pre-exist
            --pskpasswd=file       PSK password file to use
                                     - file must pre-exist
            --pskhint=str          PSK identity hint to use
            --ocsp-response=file   The OCSP response to send to client
                                     - file must pre-exist
        -p, --port=num             The port to connect to
        -l, --list                 Print a list of the supported algorithms and modes
            --provider=file        Specify the PKCS #11 provider library
                                     - file must pre-exist
        -v, --version[=arg]        output version information and exit
        -h, --help                 display extended usage information and exit
        -!, --more-help            extended usage information passed thru pager

     Options are specified by doubled hyphens and their name or by a single
     hyphen and the flag character.

     Server program that listens to incoming TLS connections.


debug option (-d)
-----------------

This is the "enable debugging" option.  This option takes a number
argument.  Specifies the debug level.

verify-client-cert option
-------------------------

This is the "if a client certificate is sent then verify it."  option.
Do not require, but if a client certificate is sent then verify it and
close the connection if invalid.

heartbeat option (-b)
---------------------

This is the "activate heartbeat support" option.  Regularly ping client
via heartbeat extension messages

priority option
---------------

This is the "priorities string" option.  This option takes a string
argument.  TLS algorithms and protocols to enable.  You can use
predefined sets of ciphersuites such as PERFORMANCE, NORMAL, SECURE128,
SECURE256.  The default is NORMAL.

Check the GnuTLS manual on section "Priority strings" for more
information on allowed keywords

ocsp-response option
--------------------

This is the "the ocsp response to send to client" option.  This option
takes a file argument.  If the client requested an OCSP response, return
data from this file to the client.

list option (-l)
----------------

This is the "print a list of the supported algorithms and modes" option.
Print a list of the supported algorithms and modes.  If a priority
string is given then only the enabled ciphersuites are shown.

provider option
---------------

This is the "specify the pkcs #11 provider library" option.  This option
takes a file argument.  This will override the default options in
/etc/gnutls/pkcs11.conf

gnutls-serv exit status
-----------------------

One of the following exit values will be returned:
'0 (EXIT_SUCCESS)'
     Successful program execution.
'1 (EXIT_FAILURE)'
     The operation failed or the command syntax was not valid.

gnutls-serv See Also
--------------------

gnutls-cli-debug(1), gnutls-cli(1)

gnutls-serv Examples
--------------------

Running your own TLS server based on GnuTLS can be useful when debugging
clients and/or GnuTLS itself.  This section describes how to use
'gnutls-serv' as a simple HTTPS server.

The most basic server can be started as:

     gnutls-serv --http --priority "NORMAL:+ANON-ECDH:+ANON-DH"

It will only support anonymous ciphersuites, which many TLS clients
refuse to use.

The next step is to add support for X.509.  First we generate a CA:

     $ certtool --generate-privkey > x509-ca-key.pem
     $ echo 'cn = GnuTLS test CA' > ca.tmpl
     $ echo 'ca' >> ca.tmpl
     $ echo 'cert_signing_key' >> ca.tmpl
     $ certtool --generate-self-signed --load-privkey x509-ca-key.pem \
       --template ca.tmpl --outfile x509-ca.pem
     ...

Then generate a server certificate.  Remember to change the dns_name
value to the name of your server host, or skip that command to avoid the
field.

     $ certtool --generate-privkey > x509-server-key.pem
     $ echo 'organization = GnuTLS test server' > server.tmpl
     $ echo 'cn = test.gnutls.org' >> server.tmpl
     $ echo 'tls_www_server' >> server.tmpl
     $ echo 'encryption_key' >> server.tmpl
     $ echo 'signing_key' >> server.tmpl
     $ echo 'dns_name = test.gnutls.org' >> server.tmpl
     $ certtool --generate-certificate --load-privkey x509-server-key.pem \
       --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
       --template server.tmpl --outfile x509-server.pem
     ...

For use in the client, you may want to generate a client certificate as
well.

     $ certtool --generate-privkey > x509-client-key.pem
     $ echo 'cn = GnuTLS test client' > client.tmpl
     $ echo 'tls_www_client' >> client.tmpl
     $ echo 'encryption_key' >> client.tmpl
     $ echo 'signing_key' >> client.tmpl
     $ certtool --generate-certificate --load-privkey x509-client-key.pem \
       --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
       --template client.tmpl --outfile x509-client.pem
     ...

To be able to import the client key/certificate into some applications,
you will need to convert them into a PKCS#12 structure.  This also
encrypts the security sensitive key with a password.

     $ certtool --to-p12 --load-ca-certificate x509-ca.pem \
       --load-privkey x509-client-key.pem --load-certificate x509-client.pem \
       --outder --outfile x509-client.p12

For icing, we'll create a proxy certificate for the client too.

     $ certtool --generate-privkey > x509-proxy-key.pem
     $ echo 'cn = GnuTLS test client proxy' > proxy.tmpl
     $ certtool --generate-proxy --load-privkey x509-proxy-key.pem \
       --load-ca-certificate x509-client.pem --load-ca-privkey x509-client-key.pem \
       --load-certificate x509-client.pem --template proxy.tmpl \
       --outfile x509-proxy.pem
     ...

Then start the server again:

     $ gnutls-serv --http \
                 --x509cafile x509-ca.pem \
                 --x509keyfile x509-server-key.pem \
                 --x509certfile x509-server.pem

Try connecting to the server using your web browser.  Note that the
server listens to port 5556 by default.

While you are at it, to allow connections using DSA, you can also create
a DSA key and certificate for the server.  These credentials will be
used in the final example below.

     $ certtool --generate-privkey --dsa > x509-server-key-dsa.pem
     $ certtool --generate-certificate --load-privkey x509-server-key-dsa.pem \
       --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
       --template server.tmpl --outfile x509-server-dsa.pem
     ...

The next step is to create OpenPGP credentials for the server.

     gpg --gen-key
     ...enter whatever details you want, use 'test.gnutls.org' as name...

Make a note of the OpenPGP key identifier of the newly generated key,
here it was '5D1D14D8'.  You will need to export the key for GnuTLS to
be able to use it.

     gpg -a --export 5D1D14D8 > openpgp-server.txt
     gpg --export 5D1D14D8 > openpgp-server.bin
     gpg --export-secret-keys 5D1D14D8 > openpgp-server-key.bin
     gpg -a --export-secret-keys 5D1D14D8 > openpgp-server-key.txt

Let's start the server with support for OpenPGP credentials:

     gnutls-serv --http --priority NORMAL:+CTYPE-OPENPGP \
                 --pgpkeyfile openpgp-server-key.txt \
                 --pgpcertfile openpgp-server.txt

The next step is to add support for SRP authentication.  This requires
an SRP password file created with 'srptool'.  To start the server with
SRP support:

     gnutls-serv --http --priority NORMAL:+SRP-RSA:+SRP \
                 --srppasswdconf srp-tpasswd.conf \
                 --srppasswd srp-passwd.txt

Let's also start a server with support for PSK. This would require a
password file created with 'psktool'.

     gnutls-serv --http --priority NORMAL:+ECDHE-PSK:+PSK \
                 --pskpasswd psk-passwd.txt

Finally, we start the server with all the earlier parameters and you get
this command:

     gnutls-serv --http --priority NORMAL:+PSK:+SRP:+CTYPE-OPENPGP \
                 --x509cafile x509-ca.pem \
                 --x509keyfile x509-server-key.pem \
                 --x509certfile x509-server.pem \
                 --x509dsakeyfile x509-server-key-dsa.pem \
                 --x509dsacertfile x509-server-dsa.pem \
                 --pgpkeyfile openpgp-server-key.txt \
                 --pgpcertfile openpgp-server.txt \
                 --srppasswdconf srp-tpasswd.conf \
                 --srppasswd srp-passwd.txt \
                 --pskpasswd psk-passwd.txt


File: gnutls.info,  Node: gnutls-cli-debug Invocation,  Prev: gnutls-serv Invocation,  Up: Other included programs

9.3 Invoking gnutls-cli-debug
=============================

TLS debug client.  It sets up multiple TLS connections to a server and
queries its capabilities.  It was created to assist in debugging GnuTLS,
but it might be useful to extract a TLS server's capabilities.  It
connects to a TLS server, performs tests and print the server's
capabilities.  If called with the '-v' parameter more checks will be
performed.  Can be used to check for servers with special needs or bugs.

This section was generated by *AutoGen*, using the 'agtexi-cmd' template
and the option descriptions for the 'gnutls-cli-debug' program.  This
software is released under the GNU General Public License, version 3 or
later.

gnutls-cli-debug help/usage ('--help')
--------------------------------------

This is the automatically generated usage text for gnutls-cli-debug.

The text printed is the same whether selected with the 'help' option
('--help') or the 'more-help' option ('--more-help').  'more-help' will
print the usage text by passing it through a pager program.  'more-help'
is disabled on platforms without a working 'fork(2)' function.  The
'PAGER' environment variable is used to select the program, defaulting
to 'more'.  Both will exit with a status code of 0.

     gnutls-cli-debug - GnuTLS debug client
     Usage:  gnutls-cli-debug [ -<flag> [<val>] | --<name>[{=| }<val>] ]...

        -d, --debug=num            Enable debugging
                                     - it must be in the range:
                                       0 to 9999
        -V, --verbose              More verbose output
                                     - may appear multiple times
        -p, --port=num             The port to connect to
                                     - it must be in the range:
                                       0 to 65536
            --app-proto=str        an alias for the 'starttls-proto' option
            --starttls-proto=str   The application protocol to be used to obtain the server's certificate
     (https, ftp, smtp, imap, ldap, xmpp)
        -v, --version[=arg]        output version information and exit
        -h, --help                 display extended usage information and exit
        -!, --more-help            extended usage information passed thru pager

     Options are specified by doubled hyphens and their name or by a single
     hyphen and the flag character.
     Operands and options may be intermixed.  They will be reordered.

     TLS debug client.  It sets up multiple TLS connections to a server and
     queries its capabilities.  It was created to assist in debugging GnuTLS,
     but it might be useful to extract a TLS server's capabilities.  It connects
     to a TLS server, performs tests and print the server's capabilities.  If
     called with the `-v' parameter more checks will be performed.  Can be used
     to check for servers with special needs or bugs.


debug option (-d)
-----------------

This is the "enable debugging" option.  This option takes a number
argument.  Specifies the debug level.

gnutls-cli-debug exit status
----------------------------

One of the following exit values will be returned:
'0 (EXIT_SUCCESS)'
     Successful program execution.
'1 (EXIT_FAILURE)'
     The operation failed or the command syntax was not valid.

gnutls-cli-debug See Also
-------------------------

gnutls-cli(1), gnutls-serv(1)

gnutls-cli-debug Examples
-------------------------

     $ ../src/gnutls-cli-debug localhost
     Resolving 'localhost'...
     Connecting to '127.0.0.1:443'...
     Checking for SSL 3.0 support... yes
     Checking whether %COMPAT is required... no
     Checking for TLS 1.0 support... yes
     Checking for TLS 1.1 support... no
     Checking fallback from TLS 1.1 to... TLS 1.0
     Checking for TLS 1.2 support... no
     Checking whether we need to disable TLS 1.0... N/A
     Checking for Safe renegotiation support... yes
     Checking for Safe renegotiation support (SCSV)... yes
     Checking for HTTPS server name... not checked
     Checking for version rollback bug in RSA PMS... no
     Checking for version rollback bug in Client Hello... no
     Checking whether the server ignores the RSA PMS version... no
     Checking whether the server can accept Hello Extensions... yes
     Checking whether the server can accept small records (512 bytes)... yes
     Checking whether the server can accept cipher suites not in SSL 3.0 spec... yes
     Checking whether the server can accept a bogus TLS record version in the client hello... yes
     Checking for certificate information... N/A
     Checking for trusted CAs... N/A
     Checking whether the server understands TLS closure alerts... partially
     Checking whether the server supports session resumption... yes
     Checking for export-grade ciphersuite support... no
     Checking RSA-export ciphersuite info... N/A
     Checking for anonymous authentication support... no
     Checking anonymous Diffie-Hellman group info... N/A
     Checking for ephemeral Diffie-Hellman support... no
     Checking ephemeral Diffie-Hellman group info... N/A
     Checking for ephemeral EC Diffie-Hellman support... yes
     Checking ephemeral EC Diffie-Hellman group info...
      Curve SECP256R1
     Checking for AES-GCM cipher support... no
     Checking for AES-CBC cipher support... yes
     Checking for CAMELLIA cipher support... no
     Checking for 3DES-CBC cipher support... yes
     Checking for ARCFOUR 128 cipher support... yes
     Checking for ARCFOUR 40 cipher support... no
     Checking for MD5 MAC support... yes
     Checking for SHA1 MAC support... yes
     Checking for SHA256 MAC support... no
     Checking for ZLIB compression support... no
     Checking for max record size... no
     Checking for OpenPGP authentication support... no


File: gnutls.info,  Node: Internal architecture of GnuTLS,  Next: Upgrading from previous versions,  Prev: Other included programs,  Up: Top

10 Internal Architecture of GnuTLS
**********************************

This chapter is to give a brief description of the way GnuTLS works.
The focus is to give an idea to potential developers and those who want
to know what happens inside the black box.

* Menu:

* The TLS Protocol::
* TLS Handshake Protocol::
* TLS Authentication Methods::
* TLS Extension Handling::
* Cryptographic Backend::


File: gnutls.info,  Node: The TLS Protocol,  Next: TLS Handshake Protocol,  Up: Internal architecture of GnuTLS

10.1 The TLS Protocol
=====================

The main use case for the TLS protocol is shown in *note Figure 10.1:
fig-client-server.  A user of a library implementing the protocol
expects no less than this functionality, i.e., to be able to set
parameters such as the accepted security level, perform a negotiation
with the peer and be able to exchange data.

[image src="gnutls-client-server-use-case.png"]

Figure 10.1: TLS protocol use case.


File: gnutls.info,  Node: TLS Handshake Protocol,  Next: TLS Authentication Methods,  Prev: The TLS Protocol,  Up: Internal architecture of GnuTLS

10.2 TLS Handshake Protocol
===========================

The GnuTLS handshake protocol is implemented as a state machine that
waits for input or returns immediately when the non-blocking transport
layer functions are used.  The main idea is shown in *note Figure 10.2:
fig-gnutls-handshake.

[image src="gnutls-handshake-state.png"]

Figure 10.2: GnuTLS handshake state machine.

Also the way the input is processed varies per ciphersuite.  Several
implementations of the internal handlers are available and *note
gnutls_handshake:: only multiplexes the input to the appropriate
handler.  For example a PSK ciphersuite has a different implementation
of the 'process_client_key_exchange' than a certificate ciphersuite.  We
illustrate the idea in *note Figure 10.3: fig-gnutls-handshake-sequence.

[image src="gnutls-handshake-sequence.png"]

Figure 10.3: GnuTLS handshake process sequence.


File: gnutls.info,  Node: TLS Authentication Methods,  Next: TLS Extension Handling,  Prev: TLS Handshake Protocol,  Up: Internal architecture of GnuTLS

10.3 TLS Authentication Methods
===============================

In GnuTLS authentication methods can be implemented quite easily.  Since
the required changes to add a new authentication method affect only the
handshake protocol, a simple interface is used.  An authentication
method needs to implement the functions shown below.

typedef struct
{
  const char *name;
  int (*gnutls_generate_server_certificate) (gnutls_session_t, gnutls_buffer_st*);
  int (*gnutls_generate_client_certificate) (gnutls_session_t, gnutls_buffer_st*);
  int (*gnutls_generate_server_kx) (gnutls_session_t, gnutls_buffer_st*);
  int (*gnutls_generate_client_kx) (gnutls_session_t, gnutls_buffer_st*);
  int (*gnutls_generate_client_cert_vrfy) (gnutls_session_t, gnutls_buffer_st *);
  int (*gnutls_generate_server_certificate_request) (gnutls_session_t,
                                                     gnutls_buffer_st *);

  int (*gnutls_process_server_certificate) (gnutls_session_t, opaque *,
                                            size_t);
  int (*gnutls_process_client_certificate) (gnutls_session_t, opaque *,
                                            size_t);
  int (*gnutls_process_server_kx) (gnutls_session_t, opaque *, size_t);
  int (*gnutls_process_client_kx) (gnutls_session_t, opaque *, size_t);
  int (*gnutls_process_client_cert_vrfy) (gnutls_session_t, opaque *, size_t);
  int (*gnutls_process_server_certificate_request) (gnutls_session_t,
                                                    opaque *, size_t);
} mod_auth_st;

Those functions are responsible for the interpretation of the handshake
protocol messages.  It is common for such functions to read data from
one or more 'credentials_t' structures(1) and write data, such as
certificates, usernames etc.  to 'auth_info_t' structures.

Simple examples of existing authentication methods can be seen in
'auth/psk.c' for PSK ciphersuites and 'auth/srp.c' for SRP ciphersuites.
After implementing these functions the structure holding its pointers
has to be registered in 'gnutls_algorithms.c' in the
'_gnutls_kx_algorithms' structure.

   ---------- Footnotes ----------

   (1) such as the 'gnutls_certificate_credentials_t' structures


File: gnutls.info,  Node: TLS Extension Handling,  Next: Cryptographic Backend,  Prev: TLS Authentication Methods,  Up: Internal architecture of GnuTLS

10.4 TLS Extension Handling
===========================

As with authentication methods, the TLS extensions handlers can be
implemented using the interface shown below.

typedef int (*gnutls_ext_recv_func) (gnutls_session_t session,
                                     const unsigned char *data, size_t len);
typedef int (*gnutls_ext_send_func) (gnutls_session_t session,
                                     gnutls_buffer_st *extdata);

Here there are two functions, one for receiving the extension data and
one for sending.  These functions have to check internally whether they
operate in client or server side.

A simple example of an extension handler can be seen in 'ext/srp.c' in
GnuTLS' source code.  After implementing these functions, together with
the extension number they handle, they have to be registered using
'_gnutls_ext_register' in 'gnutls_extensions.c' typically within
'_gnutls_ext_init'.

Adding a new TLS extension
--------------------------

Adding support for a new TLS extension is done from time to time, and
the process to do so is not difficult.  Here are the steps you need to
follow if you wish to do this yourself.  For sake of discussion, let's
consider adding support for the hypothetical TLS extension 'foobar'.

Add 'configure' option like '--enable-foobar' or '--disable-foobar'.
....................................................................

This step is useful when the extension code is large and it might be
desirable to disable the extension under some circumstances.  Otherwise
it can be safely skipped.

Whether to chose enable or disable depends on whether you intend to make
the extension be enabled by default.  Look at existing checks (i.e.,
SRP, authz) for how to model the code.  For example:

     AC_MSG_CHECKING([whether to disable foobar support])
     AC_ARG_ENABLE(foobar,
     	AS_HELP_STRING([--disable-foobar],
     		[disable foobar support]),
     	ac_enable_foobar=no)
     if test x$ac_enable_foobar != xno; then
      AC_MSG_RESULT(no)
      AC_DEFINE(ENABLE_FOOBAR, 1, [enable foobar])
     else
      ac_full=0
      AC_MSG_RESULT(yes)
     fi
     AM_CONDITIONAL(ENABLE_FOOBAR, test "$ac_enable_foobar" != "no")

These lines should go in 'm4/hooks.m4'.

Add IANA extension value to 'extensions_t' in 'gnutls_int.h'.
.............................................................

A good name for the value would be GNUTLS_EXTENSION_FOOBAR. Check with
<http://www.iana.org/assignments/tls-extensiontype-values> for allocated
values.  For experiments, you could pick a number but remember that some
consider it a bad idea to deploy such modified version since it will
lead to interoperability problems in the future when the IANA allocates
that number to someone else, or when the foobar protocol is allocated
another number.

Add an entry to '_gnutls_extensions' in 'gnutls_extensions.c'.
..............................................................

A typical entry would be:

       int ret;

     #if ENABLE_FOOBAR
       ret = _gnutls_ext_register (&foobar_ext);
       if (ret != GNUTLS_E_SUCCESS)
         return ret;
     #endif

Most likely you'll need to add an '#include "ext/foobar.h"', that will
contain something like like:
       extension_entry_st foobar_ext = {
         .name = "FOOBAR",
         .type = GNUTLS_EXTENSION_FOOBAR,
         .parse_type = GNUTLS_EXT_TLS,
         .recv_func = _foobar_recv_params,
         .send_func = _foobar_send_params,
         .pack_func = _foobar_pack,
         .unpack_func = _foobar_unpack,
         .deinit_func = NULL
       }

The GNUTLS_EXTENSION_FOOBAR is the integer value you added to
'gnutls_int.h' earlier.  In this structure you specify the functions to
read the extension from the hello message, the function to send the
reply to, and two more functions to pack and unpack from stored session
data (e.g.  when resumming a session).  The 'deinit' function will be
called to deinitialize the extension's private parameters, if any.

Note that the conditional 'ENABLE_FOOBAR' definition should only be used
if step 1 with the 'configure' options has taken place.

Add new files that implement the extension.
...........................................

The functions you are responsible to add are those mentioned in the
previous step.  They should be added in a file such as 'ext/foobar.c'
and headers should be placed in 'ext/foobar.h'.  As a starter, you could
add this:

     int
     _foobar_recv_params (gnutls_session_t session, const opaque * data,
                          size_t data_size)
     {
       return 0;
     }

     int
     _foobar_send_params (gnutls_session_t session, gnutls_buffer_st* data)
     {
       return 0;
     }

     int
     _foobar_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
     {
        /* Append the extension's internal state to buffer */
        return 0;
     }

     int
     _foobar_unpack (gnutls_buffer_st * ps, extension_priv_data_t * epriv)
     {
        /* Read the internal state from buffer */
        return 0;
     }

The '_foobar_recv_params' function is responsible for parsing incoming
extension data (both in the client and server).

The '_foobar_send_params' function is responsible for sending extension
data (both in the client and server).

If you receive length fields that don't match, return
'GNUTLS_E_UNEXPECTED_PACKET_LENGTH'.  If you receive invalid data,
return 'GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER'.  You can use other error
codes from the list in *note Error codes::.  Return 0 on success.

An extension typically stores private information in the 'session' data
for later usage.  That can be done using the functions
'_gnutls_ext_set_session_data' and '_gnutls_ext_get_session_data'.  You
can check simple examples at 'ext/max_record.c' and 'ext/server_name.c'
extensions.  That private information can be saved and restored across
session resumption if the following functions are set:

The '_foobar_pack' function is responsible for packing internal
extension data to save them in the session resumption storage.

The '_foobar_unpack' function is responsible for restoring session data
from the session resumption storage.

Recall that both the client and server, send and receive parameters, and
your code most likely will need to do different things depending on
which mode it is in.  It may be useful to make this distinction explicit
in the code.  Thus, for example, a better template than above would be:

     int
     _gnutls_foobar_recv_params (gnutls_session_t session,
                                 const opaque * data,
                                 size_t data_size)
     {
       if (session->security_parameters.entity == GNUTLS_CLIENT)
         return foobar_recv_client (session, data, data_size);
       else
         return foobar_recv_server (session, data, data_size);
     }

     int
     _gnutls_foobar_send_params (gnutls_session_t session,
                                 gnutls_buffer_st * data)
     {
       if (session->security_parameters.entity == GNUTLS_CLIENT)
         return foobar_send_client (session, data);
       else
         return foobar_send_server (session, data);
     }

The functions used would be declared as 'static' functions, of the
appropriate prototype, in the same file.  When adding the files, you'll
need to add them to 'ext/Makefile.am' as well, for example:

     if ENABLE_FOOBAR
     libgnutls_ext_la_SOURCES += ext/foobar.c ext/foobar.h
     endif

Add API functions to enable/disable the extension.
..................................................

It might be desirable to allow users of the extension to request use of
the extension, or set extension specific data.  This can be implemented
by adding extension specific function calls that can be added to
'includes/gnutls/gnutls.h', as long as the LGPLv2.1+ applies.  The
implementation of the function should lie in the 'ext/foobar.c' file.

To make the API available in the shared library you need to add the
symbol in 'lib/libgnutls.map', so that the symbol is exported properly.

When writing GTK-DOC style documentation for your new APIs, don't forget
to add 'Since:' tags to indicate the GnuTLS version the API was
introduced in.

Heartbeat extension.
....................

One such extension is HeartBeat protocol (RFC6520:
<https://tools.ietf.org/html/rfc6520>) implementation.  To enable it use
option -heartbeat with example client and server supplied with gnutls:

     ./doc/credentials/gnutls-http-serv --priority "NORMAL:-CIPHER-ALL:+NULL" -d 100 \
         --heartbeat --echo
     ./src/gnutls-cli --priority "NORMAL:-CIPHER-ALL:+NULL" -d 100 localhost -p 5556 \
         --insecure --heartbeat

After that pasting
     **HEARTBEAT**
command into gnutls-cli will trigger corresponding command on the server
and it will send HeartBeat Request with random length to client.

Another way is to run capabilities check with:

     ./doc/credentials/gnutls-http-serv -d 100 --heartbeat
     ./src/gnutls-cli-debug localhost -p 5556

Adding a new Supplemental Data Handshake Message
------------------------------------------------

TLS handshake extensions allow to send so called supplemental data
handshake messages [_RFC4680_].  This short section explains how to
implement a supplemental data handshake message for a given TLS
extension.

First of all, modify your extension 'foobar' in the way, the that flags
'session->security_parameters.do_send_supplemental' and
'session->security_parameters.do_recv_supplemental' are set:

     int
     _gnutls_foobar_recv_params (gnutls_session_t session, const opaque * data,
                                      size_t _data_size)
     {
        ...
        session->security_parameters.do_recv_supplemental=1;
        ...
     }

     int
     _gnutls_foobar_send_params (gnutls_session_t session, gnutls_buffer_st *extdata)
     {
        ...
        session->security_parameters.do_send_supplemental=1;
        ...
     }

Furthermore add the functions '_foobar_supp_recv_params' and
'_foobar_supp_send_params' to '_foobar.h' and '_foobar.c'.  The
following example code shows how to send a "Hello World" string in the
supplemental data handshake message:

     int
     _foobar_supp_recv_params(gnutls_session_t session, const opaque *data, size_t _data_size)
     {
        uint8_t len = _data_size;
        unsigned char *msg;

        msg = gnutls_malloc(len);
        if (msg == NULL) return GNUTLS_E_MEMORY_ERROR;

        memcpy(msg, data, len);
        msg[len]='\0';

        /* do something with msg */
        gnutls_free(msg);

        return len;
     }

     int
     _foobar_supp_send_params(gnutls_session_t session, gnutls_buffer_st *buf)
     {
        unsigned char *msg = "hello world";
        int len = strlen(msg);

        _gnutls_buffer_append_data_prefix(buf, 8, msg, len);

        return len;
     }

Afterwards, add the new supplemental data handshake message to
'lib/gnutls_supplemental.c' by adding a new entry to the
'_gnutls_supplemental[]' structure:

     gnutls_supplemental_entry _gnutls_supplemental[] =
     {
       {"foobar",
        GNUTLS_SUPPLEMENTAL_FOOBAR_DATA,
        _foobar_supp_recv_params,
        _foobar_supp_send_params},
       {0, 0, 0, 0}
     };

You have to include your 'foobar.h' header file as well:

     #include "foobar.h"

Lastly, add the new supplemental data type to
'lib/includes/gnutls/gnutls.h':

     typedef enum
     {
         GNUTLS_SUPPLEMENTAL_USER_MAPPING_DATA = 0,
         GNUTLS_SUPPLEMENTAL_FOOBAR_DATA = 1
     } gnutls_supplemental_data_format_type_t;


File: gnutls.info,  Node: Cryptographic Backend,  Prev: TLS Extension Handling,  Up: Internal architecture of GnuTLS

10.5 Cryptographic Backend
==========================

Today most new processors, either for embedded or desktop systems
include either instructions intended to speed up cryptographic
operations, or a co-processor with cryptographic capabilities.  Taking
advantage of those is a challenging task for every cryptographic
application or library.  Unfortunately the cryptographic library that
GnuTLS is based on takes no advantage of these capabilities.  For this
reason GnuTLS handles this internally by following a layered approach to
accessing cryptographic operations as in *note Figure 10.4:
fig-crypto-layers.

[image src="gnutls-crypto-layers.png"]

Figure 10.4: GnuTLS cryptographic back-end design.

The TLS layer uses a cryptographic provider layer, that will in turn
either use the default crypto provider - a software crypto library, or
use an external crypto provider, if available in the local system.  The
reason of handling the external cryptographic provider in GnuTLS and not
delegating it to the cryptographic libraries, is that none of the
supported cryptographic libraries support '/dev/crypto' or CPU-optimized
cryptography in an efficient way.

Cryptographic library layer
---------------------------

The Cryptographic library layer, currently supports only libnettle.
Older versions of GnuTLS used to support libgcrypt, but it was switched
with nettle mainly for performance reasons(1) and secondary because it
is a simpler library to use.  In the future other cryptographic
libraries might be supported as well.

External cryptography provider
------------------------------

Systems that include a cryptographic co-processor, typically come with
kernel drivers to utilize the operations from software.  For this reason
GnuTLS provides a layer where each individual algorithm used can be
replaced by another implementation, i.e., the one provided by the
driver.  The FreeBSD, OpenBSD and Linux kernels(2) include already a
number of hardware assisted implementations, and also provide an
interface to access them, called '/dev/crypto'.  GnuTLS will take
advantage of this interface if compiled with special options.  That is
because in most systems where hardware-assisted cryptographic operations
are not available, using this interface might actually harm performance.

In systems that include cryptographic instructions with the CPU's
instructions set, using the kernel interface will introduce an unneeded
layer.  For this reason GnuTLS includes such optimizations found in
popular processors such as the AES-NI or VIA PADLOCK instruction sets.
This is achieved using a mechanism that detects CPU capabilities and
overrides parts of crypto back-end at runtime.  The next section
discusses the registration of a detected algorithm optimization.  For
more information please consult the GnuTLS source code in
'lib/accelerated/'.

Overriding specific algorithms
..............................

When an optimized implementation of a single algorithm is available, say
a hardware assisted version of AES-CBC then the following (internal)
functions, from 'crypto-backend.h', can be used to register those
algorithms.

   * 'gnutls_crypto_single_cipher_register': To register a cipher
     algorithm.

   * 'gnutls_crypto_single_digest_register': To register a hash (digest)
     or MAC algorithm.

Those registration functions will only replace the specified algorithm
and leave the rest of subsystem intact.

Overriding the cryptographic library
....................................

In some systems, that might contain a broad acceleration engine, it
might be desirable to override big parts of the cryptographic back-end,
or even all of them.  The following functions are provided for this
reason.

   * 'gnutls_crypto_cipher_register': To override the cryptographic
     algorithms back-end.

   * 'gnutls_crypto_digest_register': To override the digest algorithms
     back-end.

   * 'gnutls_crypto_rnd_register': To override the random number
     generator back-end.

   * 'gnutls_crypto_bigint_register': To override the big number number
     operations back-end.

   * 'gnutls_crypto_pk_register': To override the public key encryption
     back-end.  This is tied to the big number operations so either none
     or both of them should be overridden.

   ---------- Footnotes ----------

   (1) See
<http://lists.gnu.org/archive/html/gnutls-devel/2011-02/msg00079.html>.

   (2) Check <http://home.gna.org/cryptodev-linux/> for the Linux kernel
implementation of '/dev/crypto'.


File: gnutls.info,  Node: Upgrading from previous versions,  Next: Support,  Prev: Internal architecture of GnuTLS,  Up: Top

Appendix A Upgrading from previous versions
*******************************************

The GnuTLS library typically maintains binary and source code
compatibility across versions.  The releases that have the major version
increased break binary compatibility but source compatibility is
provided.  This section lists exceptional cases where changes to
existing code are required due to library changes.

Upgrading to 2.12.x from previous versions
==========================================

GnuTLS 2.12.x is binary compatible with previous versions but changes
the semantics of 'gnutls_transport_set_lowat', which might cause
breakage in applications that relied on its default value be 1.  Two
fixes are proposed:
   * Quick fix.  Explicitly call 'gnutls_transport_set_lowat (session,
     1);' after *note gnutls_init::.
   * Long term fix.  Because later versions of gnutls abolish the
     functionality of using the system call 'select' to check for gnutls
     pending data, the function *note gnutls_record_check_pending:: has
     to be used to achieve the same functionality as described in *note
     Asynchronous operation::.

Upgrading to 3.0.x from 2.12.x
==============================

GnuTLS 3.0.x is source compatible with previous versions except for the
functions listed below.

Old function           Replacement
                       
-------------------------------------------------------------------
'gnutls_transport_set_lowat'To replace its functionality the function
                       *note gnutls_record_check_pending:: has
                       to be used, as described in
                       *note Asynchronous operation::
                       
'gnutls_session_get_server_random',They are replaced by the safer function
'gnutls_session_get_client_random'*note gnutls_session_get_random::
                       
'gnutls_session_get_master_secret'Replaced by the keying material exporters
                       discussed in
                       *note Deriving keys for other applications/protocols::
                       
'gnutls_transport_set_global_errno'Replaced by using the system's errno
                       fascility or
                       *note gnutls_transport_set_errno::.
                       
'gnutls_x509_privkey_verify_data'Replaced by
                       *note gnutls_pubkey_verify_data::.
                       
'gnutls_certificate_verify_peers'Replaced by
                       *note gnutls_certificate_verify_peers2::.
                       
'gnutls_psk_netconf_derive_key'Removed.  The key derivation function was
                       never standardized.
                       
'gnutls_session_set_finished_function'Removed.
                       
'gnutls_ext_register'  Removed.  Extension registration API is
                       now internal to allow easier changes in
                       the API.
                       
'gnutls_certificate_get_x509_crls',Removed to allow updating the internal
'gnutls_certificate_get_x509_cas'structures.  Replaced by
                       *note gnutls_certificate_get_issuer::.
                       
'gnutls_certificate_get_openpgp_keyring'Removed.
                       
'gnutls_ia_'           Removed.  The inner application
                       extensions were completely removed (they
                       failed to be standardized).
                       

Upgrading to 3.1.x from 3.0.x
=============================

GnuTLS 3.1.x is source and binary compatible with GnuTLS 3.0.x releases.
Few functions have been deprecated and are listed below.

Old function           Replacement
                       
-------------------------------------------------------------------
'gnutls_pubkey_verify_hash'The function
                       *note gnutls_pubkey_verify_hash2:: is
                       provided and is functionally equivalent
                       and safer to use.
                       
'gnutls_pubkey_verify_data'The function
                       *note gnutls_pubkey_verify_data2:: is
                       provided and is functionally equivalent
                       and safer to use.
                       

Upgrading to 3.2.x from 3.1.x
=============================

GnuTLS 3.2.x is source and binary compatible with GnuTLS 3.1.x releases.
Few functions have been deprecated and are listed below.

Old function           Replacement
                       
-------------------------------------------------------------------
'gnutls_privkey_sign_raw_data'The function
                       *note gnutls_privkey_sign_hash:: is
                       equivalent when the flag
                       'GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA' is
                       specified.
                       

Upgrading to 3.3.x from 3.2.x
=============================

GnuTLS 3.3.x is source and binary compatible with GnuTLS 3.2.x releases;
however there few changes in semantics which are listed below.

Old function           Replacement
                       
-------------------------------------------------------------------
'gnutls_global_init'   No longer required.  The library is
                       initialized using a constructor.
                       
'gnutls_global_deinit' No longer required.  The library is
                       deinitialized using a destructor.
                       


File: gnutls.info,  Node: Support,  Next: Error codes,  Prev: Upgrading from previous versions,  Up: Top

Appendix B Support
******************

* Menu:

* Getting help::
* Commercial Support::
* Bug Reports::
* Contributing::
* Certification::


File: gnutls.info,  Node: Getting help,  Next: Commercial Support,  Up: Support

B.1 Getting Help
================

A mailing list where users may help each other exists, and you can reach
it by sending e-mail to <gnutls-help@gnutls.org>.  Archives of the
mailing list discussions, and an interface to manage subscriptions, is
available through the World Wide Web at
<http://lists.gnutls.org/pipermail/gnutls-help/>.

A mailing list for developers are also available, see
<http://www.gnutls.org/lists.html>.  Bug reports should be sent to
<bugs@gnutls.org>, see *note Bug Reports::.


File: gnutls.info,  Node: Commercial Support,  Next: Bug Reports,  Prev: Getting help,  Up: Support

B.2 Commercial Support
======================

Commercial support is available for users of GnuTLS. The kind of support
that can be purchased may include:

   * Implement new features.  Such as a new TLS extension.

   * Port GnuTLS to new platforms.  This could include porting to an
     embedded platforms that may need memory or size optimization.

   * Integrating TLS as a security environment in your existing project.

   * System design of components related to TLS.

If you are interested, please write to:

Simon Josefsson Datakonsult
Hagagatan 24
113 47 Stockholm
Sweden

E-mail: simon@josefsson.org

If your company provides support related to GnuTLS and would like to be
mentioned here, contact the authors.


File: gnutls.info,  Node: Bug Reports,  Next: Contributing,  Prev: Commercial Support,  Up: Support

B.3 Bug Reports
===============

If you think you have found a bug in GnuTLS, please investigate it and
report it.

   * Please make sure that the bug is really in GnuTLS, and preferably
     also check that it hasn't already been fixed in the latest version.

   * You have to send us a test case that makes it possible for us to
     reproduce the bug.

   * You also have to explain what is wrong; if you get a crash, or if
     the results printed are not good and in that case, in what way.
     Make sure that the bug report includes all information you would
     need to fix this kind of bug for someone else.

Please make an effort to produce a self-contained report, with something
definite that can be tested or debugged.  Vague queries or piecemeal
messages are difficult to act on and don't help the development effort.

If your bug report is good, we will do our best to help you to get a
corrected version of the software; if the bug report is poor, we won't
do anything about it (apart from asking you to send better bug reports).

If you think something in this manual is unclear, or downright
incorrect, or if the language needs to be improved, please also send a
note.

Send your bug report to:

                           'bugs@gnutls.org'


File: gnutls.info,  Node: Contributing,  Next: Certification,  Prev: Bug Reports,  Up: Support

B.4 Contributing
================

If you want to submit a patch for inclusion - from solving a typo you
discovered, up to adding support for a new feature - you should submit
it as a bug report, using the process in *note Bug Reports::.  There are
some things that you can do to increase the chances for it to be
included in the official package.

Unless your patch is very small (say, under 10 lines) we require that
you assign the copyright of your work to the Free Software Foundation.
This is to protect the freedom of the project.  If you have not already
signed papers, we will send you the necessary information when you
submit your contribution.

For contributions that doesn't consist of actual programming code, the
only guidelines are common sense.  For code contributions, a number of
style guides will help you:

   * Coding Style.  Follow the GNU Standards document.

     If you normally code using another coding standard, there is no
     problem, but you should use 'indent' to reformat the code before
     submitting your work.

   * Use the unified diff format 'diff -u'.

   * Return errors.  No reason whatsoever should abort the execution of
     the library.  Even memory allocation errors, e.g.  when malloc
     return NULL, should work although result in an error code.

   * Design with thread safety in mind.  Don't use global variables.
     Don't even write to per-handle global variables unless the
     documented behaviour of the function you write is to write to the
     per-handle global variable.

   * Avoid using the C math library.  It causes problems for embedded
     implementations, and in most situations it is very easy to avoid
     using it.

   * Document your functions.  Use comments before each function
     headers, that, if properly formatted, are extracted into Texinfo
     manuals and GTK-DOC web pages.

   * Supply a ChangeLog and NEWS entries, where appropriate.

