summaryrefslogtreecommitdiffstats
path: root/doc/gnutls.info-2
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:33:12 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 07:33:12 +0000
commit36082a2fe36ecd800d784ae44c14f1f18c66a7e9 (patch)
tree6c68e0c0097987aff85a01dabddd34b862309a7c /doc/gnutls.info-2
parentInitial commit. (diff)
downloadgnutls28-36082a2fe36ecd800d784ae44c14f1f18c66a7e9.tar.xz
gnutls28-36082a2fe36ecd800d784ae44c14f1f18c66a7e9.zip
Adding upstream version 3.7.9.upstream/3.7.9upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/gnutls.info-2')
-rw-r--r--doc/gnutls.info-27184
1 files changed, 7184 insertions, 0 deletions
diff --git a/doc/gnutls.info-2 b/doc/gnutls.info-2
new file mode 100644
index 0000000..65ff97b
--- /dev/null
+++ b/doc/gnutls.info-2
@@ -0,0 +1,7184 @@
+This is gnutls.info, produced by makeinfo version 6.8 from gnutls.texi.
+
+This manual is last updated 9 February 2023 for version 3.7.9 of GnuTLS.
+
+Copyright (C) 2001-2023 Free Software Foundation, Inc.\\ Copyright (C)
+2001-2023 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)certtool Invocation. Manipulate certificates and keys.
+* gnutls-serv: (gnutls)gnutls-serv Invocation. GnuTLS test server.
+* gnutls-cli: (gnutls)gnutls-cli Invocation. GnuTLS test client.
+* gnutls-cli-debug: (gnutls)gnutls-cli-debug Invocation. GnuTLS debug client.
+* psktool: (gnutls)psktool Invocation. Simple TLS-Pre-Shared-Keys manager.
+* srptool: (gnutls)srptool Invocation. Simple SRP password tool.
+END-INFO-DIR-ENTRY
+
+
+File: gnutls.info, Node: Trusted Platform Module, Prev: Smart cards and HSMs, Up: Hardware security modules and abstract key types
+
+5.4 Trusted Platform Module (TPM)
+=================================
+
+In this section we present the Trusted Platform Module (TPM) support in
+GnuTLS. Note that we recommend against using TPM with this API because
+it is restricted to TPM 1.2. We recommend instead to use PKCS#11
+wrappers for TPM such as CHAPS(1) or opencryptoki(2). These will allow
+using the standard smart card and HSM functionality (see *note Smart
+cards and HSMs::) for TPM keys.
+
+There was a big hype when the TPM chip was introduced into computers.
+Briefly it is a co-processor in your PC that allows it to perform
+calculations independently of the main processor. This has good and bad
+side-effects. In this section we focus on the good ones; these are the
+fact that you can use the TPM chip to perform cryptographic operations
+on keys stored in it, without accessing them. That is very similar to
+the operation of a PKCS #11 smart card. The chip allows for storage and
+usage of RSA keys, but has quite some operational differences from PKCS
+#11 module, and thus require different handling. The basic TPM
+operations supported and used by GnuTLS, are key generation and signing.
+That support is currently limited to TPM 1.2.
+
+The next sections assume that the TPM chip in the system is already
+initialized and in a operational state. If not, ensure that the TPM
+chip is enabled by your BIOS, that the 'tcsd' daemon is running, and
+that TPM ownership is set (by running 'tpm_takeownership').
+
+In GnuTLS the TPM functionality is available in 'gnutls/tpm.h'.
+
+* Menu:
+
+* Keys in TPM::
+* Key generation::
+* Using keys::
+* tpmtool Invocation::
+
+ ---------- Footnotes ----------
+
+ (1) <https://github.com/google/chaps-linux>
+
+ (2) <https://sourceforge.net/projects/opencryptoki/>
+
+
+File: gnutls.info, Node: Keys in TPM, Next: Key generation, Up: Trusted Platform Module
+
+5.4.1 Keys in TPM
+-----------------
+
+The RSA keys in the TPM module may either be stored in a flash memory
+within TPM or stored in a file in disk. In the former case the key can
+provide operations as with PKCS #11 and is identified by a URL. The URL
+is described in [*note TPMURI::] and is of the following form.
+tpmkey:uuid=42309df8-d101-11e1-a89a-97bb33c23ad1;storage=user
+
+It consists from a unique identifier of the key as well as the part of
+the flash memory the key is stored at. The two options for the storage
+field are 'user' and 'system'. The user keys are typically only
+available to the generating user and the system keys to all users. The
+stored in TPM keys are called registered keys.
+
+The keys that are stored in the disk are exported from the TPM but in an
+encrypted form. To access them two passwords are required. The first
+is the TPM Storage Root Key (SRK), and the other is a key-specific
+password. Also those keys are identified by a URL of the form:
+tpmkey:file=/path/to/file
+
+When objects require a PIN to be accessed the same callbacks as with
+PKCS #11 objects are expected (see *note Accessing objects that require
+a PIN::). Note that the PIN function may be called multiple times to
+unlock the SRK and the specific key in use. The label in the key
+function will then be set to 'SRK' when unlocking the SRK key, or to
+'TPM' when unlocking any other key.
+
+
+File: gnutls.info, Node: Key generation, Next: Using keys, Prev: Keys in TPM, Up: Trusted Platform Module
+
+5.4.2 Key generation
+--------------------
+
+All keys used by the TPM must be generated by the TPM. This can be done
+using *note gnutls_tpm_privkey_generate::.
+
+ -- Function: int gnutls_tpm_privkey_generate (gnutls_pk_algorithm_t PK,
+ unsigned int BITS, const char * SRK_PASSWORD, const char *
+ KEY_PASSWORD, gnutls_tpmkey_fmt_t FORMAT,
+ gnutls_x509_crt_fmt_t PUB_FORMAT, gnutls_datum_t * PRIVKEY,
+ gnutls_datum_t * PUBKEY, unsigned int FLAGS)
+ PK: the public key algorithm
+
+ BITS: the security bits
+
+ SRK_PASSWORD: a password to protect the exported key (optional)
+
+ KEY_PASSWORD: the password for the TPM (optional)
+
+ FORMAT: the format of the private key
+
+ PUB_FORMAT: the format of the public key
+
+ PRIVKEY: the generated key
+
+ PUBKEY: the corresponding public key (may be null)
+
+ FLAGS: should be a list of GNUTLS_TPM_* flags
+
+ This function will generate a private key in the TPM chip. The
+ private key will be generated within the chip and will be exported
+ in a wrapped with TPM's master key form. Furthermore the wrapped
+ key can be protected with the provided 'password' .
+
+ Note that bits in TPM is quantized value. If the input value is
+ not one of the allowed values, then it will be quantized to one of
+ 512, 1024, 2048, 4096, 8192 and 16384.
+
+ Allowed flags are:
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise a negative error value.
+
+ *Since:* 3.1.0
+
+'INT *note gnutls_tpm_get_registered:: (gnutls_tpm_key_list_t * LIST)'
+'VOID *note gnutls_tpm_key_list_deinit:: (gnutls_tpm_key_list_t LIST)'
+'INT *note gnutls_tpm_key_list_get_url:: (gnutls_tpm_key_list_t LIST, unsigned int IDX, char ** URL, unsigned int FLAGS)'
+
+ -- Function: int gnutls_tpm_privkey_delete (const char * URL, const
+ char * SRK_PASSWORD)
+ URL: the URL describing the key
+
+ SRK_PASSWORD: a password for the SRK key
+
+ This function will unregister the private key from the TPM chip.
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise a negative error value.
+
+ *Since:* 3.1.0
+
+
+File: gnutls.info, Node: Using keys, Next: tpmtool Invocation, Prev: Key generation, Up: Trusted Platform Module
+
+5.4.3 Using keys
+----------------
+
+Importing keys
+..............
+
+The TPM keys can be used directly by the abstract key types and do not
+require any special structures. Moreover functions like *note
+gnutls_certificate_set_x509_key_file2:: can access TPM URLs.
+
+'INT *note gnutls_privkey_import_tpm_raw:: (gnutls_privkey_t PKEY, const gnutls_datum_t * FDATA, gnutls_tpmkey_fmt_t FORMAT, const char * SRK_PASSWORD, const char * KEY_PASSWORD, unsigned int FLAGS)'
+'INT *note gnutls_pubkey_import_tpm_raw:: (gnutls_pubkey_t PKEY, const gnutls_datum_t * FDATA, gnutls_tpmkey_fmt_t FORMAT, const char * SRK_PASSWORD, unsigned int FLAGS)'
+
+ -- Function: int gnutls_privkey_import_tpm_url (gnutls_privkey_t PKEY,
+ const char * URL, const char * SRK_PASSWORD, const char *
+ KEY_PASSWORD, unsigned int FLAGS)
+ PKEY: The private key
+
+ URL: The URL of the TPM key to be imported
+
+ SRK_PASSWORD: The password for the SRK key (optional)
+
+ KEY_PASSWORD: A password for the key (optional)
+
+ FLAGS: One of the GNUTLS_PRIVKEY_* flags
+
+ This function will import the given private key to the abstract
+ 'gnutls_privkey_t' type.
+
+ Note that unless 'GNUTLS_PRIVKEY_DISABLE_CALLBACKS' is specified,
+ if incorrect (or NULL) passwords are given the PKCS11 callback
+ functions will be used to obtain the correct passwords. Otherwise
+ if the SRK password is wrong 'GNUTLS_E_TPM_SRK_PASSWORD_ERROR' is
+ returned and if the key password is wrong or not provided then
+ 'GNUTLS_E_TPM_KEY_PASSWORD_ERROR' is returned.
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise a negative error value.
+
+ *Since:* 3.1.0
+
+ -- Function: int gnutls_pubkey_import_tpm_url (gnutls_pubkey_t PKEY,
+ const char * URL, const char * SRK_PASSWORD, unsigned int
+ FLAGS)
+ PKEY: The public key
+
+ URL: The URL of the TPM key to be imported
+
+ SRK_PASSWORD: The password for the SRK key (optional)
+
+ FLAGS: should be zero
+
+ This function will import the given private key to the abstract
+ 'gnutls_privkey_t' type.
+
+ Note that unless 'GNUTLS_PUBKEY_DISABLE_CALLBACKS' is specified, if
+ incorrect (or NULL) passwords are given the PKCS11 callback
+ functions will be used to obtain the correct passwords. Otherwise
+ if the SRK password is wrong 'GNUTLS_E_TPM_SRK_PASSWORD_ERROR' is
+ returned.
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise a negative error value.
+
+ *Since:* 3.1.0
+
+Listing and deleting keys
+.........................
+
+The registered keys (that are stored in the TPM) can be listed using one
+of the following functions. Those keys are unfortunately only
+identified by their UUID and have no label or other human friendly
+identifier. Keys can be deleted from permanent storage using *note
+gnutls_tpm_privkey_delete::.
+
+'INT *note gnutls_tpm_get_registered:: (gnutls_tpm_key_list_t * LIST)'
+'VOID *note gnutls_tpm_key_list_deinit:: (gnutls_tpm_key_list_t LIST)'
+'INT *note gnutls_tpm_key_list_get_url:: (gnutls_tpm_key_list_t LIST, unsigned int IDX, char ** URL, unsigned int FLAGS)'
+
+ -- Function: int gnutls_tpm_privkey_delete (const char * URL, const
+ char * SRK_PASSWORD)
+ URL: the URL describing the key
+
+ SRK_PASSWORD: a password for the SRK key
+
+ This function will unregister the private key from the TPM chip.
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise a negative error value.
+
+ *Since:* 3.1.0
+
+
+File: gnutls.info, Node: tpmtool Invocation, Prev: Using keys, Up: Trusted Platform Module
+
+5.4.4 Invoking tpmtool
+----------------------
+
+Program that allows handling cryptographic data from the TPM chip.
+
+tpmtool help/usage ('-?')
+.........................
+
+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.
+
+ tpmtool - GnuTLS TPM tool
+ Usage: tpmtool [ -<flag> [<val>] | --<name>[{=| }<val>] ]...
+
+ None:
+
+ -d, --debug=num Enable debugging
+ - it must be in the range:
+ 0 to 9999
+ --infile=file Input file
+ - file must pre-exist
+ --outfile=str Output file
+ --generate-rsa Generate an RSA private-public key pair
+ --register Any generated key will be registered in the TPM
+ - requires the option 'generate-rsa'
+ --signing Any generated key will be a signing key
+ - prohibits the option 'legacy'
+ - requires the option 'generate-rsa'
+ --legacy Any generated key will be a legacy key
+ - prohibits the option 'signing'
+ - requires the option 'generate-rsa'
+ --user Any registered key will be a user key
+ - prohibits the option 'system'
+ - requires the option 'register'
+ --system Any registered key will be a system key
+ - prohibits the option 'user'
+ - requires the option 'register'
+ --pubkey=str Prints the public key of the provided key
+ --list Lists all stored keys in the TPM
+ --delete=str Delete the key identified by the given URL (UUID)
+ --test-sign=str Tests the signature operation of the provided object
+ --sec-param=str Specify the security level [low, legacy, medium, high, ultra]
+ --bits=num Specify the number of bits for key generate
+ --inder Use the DER format for keys
+ --outder Use DER format for output keys
+ --srk-well-known SRK has well known password (20 bytes of zeros)
+
+ Version, usage and configuration options:
+
+ -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.
+
+ Program that allows handling cryptographic data from the TPM chip.
+
+ Please send bug reports to: <bugs@gnutls.org>
+
+
+debug option (-d).
+..................
+
+This is the "enable debugging" option. This option takes a
+ArgumentType.NUMBER argument. Specifies the debug level.
+
+generate-rsa option.
+....................
+
+This is the "generate an rsa private-public key pair" option. Generates
+an RSA private-public key pair in the TPM chip. The key may be stored
+in file system and protected by a PIN, or stored (registered) in the TPM
+chip flash.
+
+user option.
+............
+
+This is the "any registered key will be a user key" option.
+
+This option has some usage constraints. It:
+ * must not appear in combination with any of the following options:
+ system.
+ * must appear in combination with the following options: register.
+
+The generated key will be stored in a user specific persistent storage.
+
+system option.
+..............
+
+This is the "any registered key will be a system key" option.
+
+This option has some usage constraints. It:
+ * must not appear in combination with any of the following options:
+ user.
+ * must appear in combination with the following options: register.
+
+The generated key will be stored in system persistent storage.
+
+test-sign option.
+.................
+
+This is the "tests the signature operation of the provided object"
+option. This option takes a ArgumentType.STRING argument 'url'. It can
+be used to test the correct operation of the signature operation. This
+operation will sign and verify the signed data.
+
+sec-param option.
+.................
+
+This is the "specify the security level [low, legacy, medium, high,
+ultra]" option. This option takes a ArgumentType.STRING argument
+'Security parameter'. This is alternative to the bits option. Note
+however that the values allowed by the TPM chip are quantized and given
+values may be rounded up.
+
+inder option.
+.............
+
+This is the "use the der format for keys" option. The input files will
+be assumed to be in the portable DER format of TPM. The default format
+is a custom format used by various TPM tools
+
+outder option.
+..............
+
+This is the "use der format for output keys" option. The output will be
+in the TPM portable DER format.
+
+version option (-v).
+....................
+
+This is the "output version information and exit" option. This option
+takes a ArgumentType.KEYWORD argument. Output version of program and
+exit. The default mode is 'v', a simple version. The 'c' mode will
+print copyright information and 'n' will print the full copyright
+notice.
+
+help option (-h).
+.................
+
+This is the "display extended usage information and exit" option.
+Display usage information and exit.
+
+more-help option (-!).
+......................
+
+This is the "extended usage information passed thru pager" option. Pass
+the extended usage information through a pager.
+
+tpmtool 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.
+
+tpmtool See Also
+................
+
+p11tool (1), certtool (1)
+
+tpmtool Examples
+................
+
+To generate a key that is to be stored in file system use:
+ $ tpmtool --generate-rsa --bits 2048 --outfile tpmkey.pem
+
+To generate a key that is to be stored in TPM's flash use:
+ $ tpmtool --generate-rsa --bits 2048 --register --user
+
+To get the public key of a TPM key use:
+ $ tpmtool --pubkey tpmkey:uuid=58ad734b-bde6-45c7-89d8-756a55ad1891;storage=user \
+ --outfile pubkey.pem
+
+or if the key is stored in the file system:
+ $ tpmtool --pubkey tpmkey:file=tmpkey.pem --outfile pubkey.pem
+
+To list all keys stored in TPM use:
+ $ tpmtool --list
+
+
+File: gnutls.info, Node: How to use GnuTLS in applications, Next: GnuTLS application examples, Prev: Hardware security modules and abstract key types, Up: Top
+
+6 How to use GnuTLS in applications
+***********************************
+
+* Menu:
+
+* Introduction to the library::
+* Preparation::
+* Session initialization::
+* Associating the credentials::
+* Setting up the transport layer::
+* TLS handshake::
+* Data transfer and termination::
+* Buffered data transfer::
+* Handling alerts::
+* Priority Strings::
+* Selecting cryptographic key sizes::
+* Advanced topics::
+
+
+File: gnutls.info, Node: Introduction to the library, Next: Preparation, Up: How to use GnuTLS in applications
+
+6.1 Introduction
+================
+
+This chapter tries to explain the basic functionality of the current
+GnuTLS library. Note that there may be additional functionality not
+discussed here but included in the library. Checking the header files
+in '/usr/include/gnutls/' and the manpages is recommended.
+
+* Menu:
+
+* General idea::
+* Error handling::
+* Common types::
+* Debugging and auditing::
+* Thread safety::
+* Running in a sandbox::
+* Sessions and fork::
+* Callback functions::
+
+
+File: gnutls.info, Node: General idea, Next: Error handling, Up: Introduction to the library
+
+6.1.1 General idea
+------------------
+
+A brief description of how GnuTLS sessions operate is shown at *note
+Figure 6.1: fig-gnutls-design. This section will become more clear when
+it is completely read. As shown in the figure, there is a read-only
+global state that is initialized once by the global initialization
+function. This global structure, among others, contains the memory
+allocation functions used, structures needed for the ASN.1 parser and
+depending on the system's CPU, pointers to hardware accelerated
+encryption functions. This structure is never modified by any GnuTLS
+function, except for the deinitialization function which frees all
+allocated memory and must be called after the program has permanently
+finished using GnuTLS.
+
+
+
+
+
+Figure 6.1: High level design of GnuTLS.
+
+The credentials structures are used by the authentication methods, such
+as certificate authentication. They store certificates, privates keys,
+and other information that is needed to prove the identity to the peer,
+and/or verify the identity of the peer. The information stored in the
+credentials structures is initialized once and then can be shared by
+many TLS sessions.
+
+A GnuTLS session contains all the required state and information to
+handle one secure connection. The session communicates with the peers
+using the provided functions of the transport layer. Every session has
+a unique session ID shared with the peer.
+
+Since TLS sessions can be resumed, servers need a database back-end to
+hold the session's parameters. Every GnuTLS session after a successful
+handshake calls the appropriate back-end function (see *note resume::)
+to store the newly negotiated session. The session database is examined
+by the server just after having received the client hello(1), and if the
+session ID sent by the client, matches a stored session, the stored
+session will be retrieved, and the new session will be a resumed one,
+and will share the same session ID with the previous one.
+
+ ---------- Footnotes ----------
+
+ (1) The first message in a TLS handshake
+
+
+File: gnutls.info, Node: Error handling, Next: Common types, Prev: General idea, Up: Introduction to the library
+
+6.1.2 Error handling
+--------------------
+
+There two types of GnuTLS functions. The first type returns a boolean
+value, true (non-zero) or false (zero) value; these functions are
+defined to return an unsigned integer type. The other type returns a
+signed integer type with zero (or a positive number) indicating success
+and a negative value indicating failure. For the latter type it is
+recommended to check for errors as following.
+ ret = gnutls_function();
+ if (ret < 0) {
+ return -1;
+ }
+The above example checks for a failure condition rather than for
+explicit success (e.g., equality to zero). That has the advantage that
+future extensions of the API can be extended to provide additional
+information via positive returned values (see for example *note
+gnutls_certificate_set_x509_key_file::).
+
+For certain operations such as TLS handshake and TLS packet receive
+there is the notion of fatal and non-fatal error codes. Fatal errors
+terminate the TLS session immediately and further sends and receives
+will be disallowed. Such an example is 'GNUTLS_E_DECRYPTION_FAILED'.
+Non-fatal errors may warn about something, i.e., a warning alert was
+received, or indicate the some action has to be taken. This is the case
+with the error code 'GNUTLS_E_REHANDSHAKE' returned by *note
+gnutls_record_recv::. This error code indicates that the server
+requests a re-handshake. The client may ignore this request, or may
+reply with an alert. You can test if an error code is a fatal one by
+using the *note gnutls_error_is_fatal::. All errors can be converted to
+a descriptive string using *note gnutls_strerror::.
+
+If any non fatal errors, that require an action, are to be returned by a
+function, these error codes will be documented in the function's
+reference. For example the error codes
+'GNUTLS_E_WARNING_ALERT_RECEIVED' and 'GNUTLS_E_FATAL_ALERT_RECEIVED'
+that may returned when receiving data, should be handled by notifying
+the user of the alert (as explained in *note Handling alerts::). See
+*note Error codes::, for a description of the available error codes.
+
+
+File: gnutls.info, Node: Common types, Next: Debugging and auditing, Prev: Error handling, Up: Introduction to the library
+
+6.1.3 Common types
+------------------
+
+All strings that are to provided as input to GnuTLS functions should be
+in UTF-8 unless otherwise specified. Output strings are also in UTF-8
+format unless otherwise specified. When functions take as input
+passwords, they will normalize them using [*note RFC7613::] rules (since
+GnuTLS 3.5.7).
+
+When data of a fixed size are provided to GnuTLS functions then the
+helper structure 'gnutls_datum_t' is often used. Its definition is
+shown below.
+ typedef struct
+ {
+ unsigned char *data;
+ unsigned int size;
+ } gnutls_datum_t;
+
+In functions where this structure is a returned type, if the function
+succeeds, it is expected from the caller to use 'gnutls_free()' to
+deinitialize the data element after use, unless otherwise specified. If
+the function fails, the contents of the 'gnutls_datum_t' should be
+considered undefined and must not be deinitialized.
+
+Other functions that require data for scattered read use a structure
+similar to 'struct iovec' typically used by 'readv'. It is shown below.
+ typedef struct
+ {
+ void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes to transfer */
+ } giovec_t;
+
+
+File: gnutls.info, Node: Debugging and auditing, Next: Thread safety, Prev: Common types, Up: Introduction to the library
+
+6.1.4 Debugging and auditing
+----------------------------
+
+In many cases things may not go as expected and further information, to
+assist debugging, from GnuTLS is desired. Those are the cases where the
+*note gnutls_global_set_log_level:: and *note
+gnutls_global_set_log_function:: are to be used. Those will print
+verbose information on the GnuTLS functions internal flow.
+
+'VOID *note gnutls_global_set_log_level:: (int LEVEL)'
+'VOID *note gnutls_global_set_log_function:: (gnutls_log_func LOG_FUNC)'
+
+Alternatively the environment variable 'GNUTLS_DEBUG_LEVEL' can be set
+to a logging level and GnuTLS will output debugging output to standard
+error. Other available environment variables are shown in *note Table
+6.1: tab:environment.
+
+Variable Purpose
+
+--------------------------------------------------------------------------
+'GNUTLS_DEBUG_LEVEL' When set to a numeric value, it sets the default
+ debugging level for GnuTLS applications.
+
+'SSLKEYLOGFILE' When set to a filename, GnuTLS will append to it
+ the session keys in the NSS Key Log format.
+ That format can be read by wireshark and will
+ allow decryption of the session for debugging.
+
+'GNUTLS_CPUID_OVERRIDE'That environment variable can be used to
+ explicitly enable/disable the use of certain CPU
+ capabilities. Note that CPU detection cannot be
+ overridden, i.e., VIA options cannot be enabled
+ on an Intel CPU. The currently available options
+ are:
+ * 0x1: Disable all run-time detected
+ optimizations
+ * 0x2: Enable AES-NI
+ * 0x4: Enable SSSE3
+ * 0x8: Enable PCLMUL
+ * 0x10: Enable AVX
+ * 0x20: Enable SHA_NI
+ * 0x100000: Enable VIA padlock
+ * 0x200000: Enable VIA PHE
+ * 0x400000: Enable VIA PHE SHA512
+
+'GNUTLS_FORCE_FIPS_MODE'In setups where GnuTLS is compiled with support
+ for FIPS140-2 (see *note FIPS140-2 mode::) if
+ set to one it will force the FIPS mode
+ enablement.
+
+
+
+Table 6.1: Environment variables used by the library.
+
+When debugging is not required, important issues, such as detected
+attacks on the protocol still need to be logged. This is provided by
+the logging function set by *note
+gnutls_global_set_audit_log_function::. The provided function will
+receive an message and the corresponding TLS session. The session
+information might be used to derive IP addresses or other information
+about the peer involved.
+
+ -- Function: void gnutls_global_set_audit_log_function
+ (gnutls_audit_log_func LOG_FUNC)
+ LOG_FUNC: it is the audit log function
+
+ This is the function to set the audit logging function. This is a
+ function to report important issues, such as possible attacks in
+ the protocol. This is different from
+ 'gnutls_global_set_log_function()' because it will report also
+ session-specific events. The session parameter will be null if
+ there is no corresponding TLS session.
+
+ 'gnutls_audit_log_func' is of the form, void
+ (*gnutls_audit_log_func)( gnutls_session_t, const char*);
+
+ *Since:* 3.0
+
+
+File: gnutls.info, Node: Thread safety, Next: Running in a sandbox, Prev: Debugging and auditing, Up: Introduction to the library
+
+6.1.5 Thread safety
+-------------------
+
+The GnuTLS library is thread safe by design, meaning that objects of the
+library such as TLS sessions, can be safely divided across threads as
+long as a single thread accesses a single object. This is sufficient to
+support a server which handles several sessions per thread. Read-only
+access to objects, for example the credentials holding structures, is
+also thread-safe.
+
+A 'gnutls_session_t' object could also be shared by two threads, one
+sending, the other receiving. However, care must be taken on the
+following use cases:
+ * The re-handshake process in TLS 1.2 or earlier must be handled only
+ in a single thread and no other thread may be performing any
+ operation.
+ * The flag 'GNUTLS_AUTO_REAUTH' cannot be used safely in this mode of
+ operation.
+ * Any other operation which may send or receive data, like key update
+ (c.f., *note gnutls_session_key_update::), must not be performed
+ while threads are receiving or writing.
+ * The termination of a session should be handled, either by a single
+ thread being active, or by the sender thread using *note
+ gnutls_bye:: with 'GNUTLS_SHUT_WR' and the receiving thread waiting
+ for a return value of zero (or timeout on certain servers which do
+ not respond).
+ * The functions *note gnutls_transport_set_errno:: and *note
+ gnutls_record_get_direction:: should not be relied during parallel
+ operation.
+
+For several aspects of the library (e.g., the random generator, PKCS#11
+operations), the library may utilize mutex locks (e.g., pthreads on
+GNU/Linux and CriticalSection on Windows) which are transparently setup
+on library initialization. Prior to version 3.3.0 these were setup by
+explicitly calling *note gnutls_global_init::.(1)
+
+Note that, on Glibc systems, unless the application is explicitly linked
+with the libpthread library, no mutex locks are used and setup by
+GnuTLS. It will use the Glibc mutex stubs.
+
+ ---------- Footnotes ----------
+
+ (1) On special systems you could manually specify the locking system
+using the function *note gnutls_global_set_mutex:: before calling any
+other GnuTLS function. Setting mutexes manually is not recommended.
+
+
+File: gnutls.info, Node: Running in a sandbox, Next: Sessions and fork, Prev: Thread safety, Up: Introduction to the library
+
+6.1.6 Running in a sandbox
+--------------------------
+
+Given that TLS protocol handling as well as X.509 certificate parsing
+are complicated processes involving several thousands lines of code, it
+is often desirable (and recommended) to run the TLS session handling in
+a sandbox like seccomp. That has to be allowed by the overall software
+design, but if available, it adds an additional layer of protection by
+preventing parsing errors from becoming vessels for further security
+issues such as code execution.
+
+GnuTLS requires the following system calls to be available for its
+proper operation.
+
+ * nanosleep
+ * time
+ * gettimeofday
+ * clock_gettime
+ * getrusage
+ * getpid
+ * send
+ * recv
+ * sendmsg
+ * read (to read from /dev/urandom)
+ * getrandom (this is Linux-kernel specific)
+ * poll
+
+As well as any calls needed for memory allocation to work. Note
+however, that GnuTLS depends on libc for the system calls, and there is
+no guarantee that libc will call the expected system call. For that it
+is recommended to test your program in all the targeted platforms when
+filters like seccomp are in place.
+
+An example with a seccomp filter from GnuTLS' test suite is at:
+<https://gitlab.com/gnutls/gnutls/blob/master/tests/seccomp.c>.
+
+
+File: gnutls.info, Node: Sessions and fork, Next: Callback functions, Prev: Running in a sandbox, Up: Introduction to the library
+
+6.1.7 Sessions and fork
+-----------------------
+
+A 'gnutls_session_t' object can be shared by two processes after a fork,
+one sending, the other receiving. In that case rehandshakes, cannot and
+must not be performed. As with threads, the termination of a session
+should be handled by the sender process using *note gnutls_bye:: with
+'GNUTLS_SHUT_WR' and the receiving process waiting for a return value of
+zero.
+
+
+File: gnutls.info, Node: Callback functions, Prev: Sessions and fork, Up: Introduction to the library
+
+6.1.8 Callback functions
+------------------------
+
+There are several cases where GnuTLS may need out of band input from
+your program. This is now implemented using some callback functions,
+which your program is expected to register.
+
+An example of this type of functions are the push and pull callbacks
+which are used to specify the functions that will retrieve and send data
+to the transport layer.
+
+'VOID *note gnutls_transport_set_push_function:: (gnutls_session_t SESSION, gnutls_push_func PUSH_FUNC)'
+'VOID *note gnutls_transport_set_pull_function:: (gnutls_session_t SESSION, gnutls_pull_func PULL_FUNC)'
+
+Other callback functions may require more complicated input and data to
+be allocated. Such an example is *note
+gnutls_srp_set_server_credentials_function::. All callbacks should
+allocate and free memory using 'gnutls_malloc' and 'gnutls_free'.
+
+
+File: gnutls.info, Node: Preparation, Next: Session initialization, Prev: Introduction to the library, Up: How to use GnuTLS in applications
+
+6.2 Preparation
+===============
+
+To use GnuTLS, you have to perform some changes to your sources and your
+build system. The necessary changes are explained in the following
+subsections.
+
+* Menu:
+
+* Headers::
+* Initialization::
+* Version check::
+* Building the source::
+
+
+File: gnutls.info, Node: Headers, Next: Initialization, Up: Preparation
+
+6.2.1 Headers
+-------------
+
+All the data types and functions of the GnuTLS library are defined in
+the header file 'gnutls/gnutls.h'. This must be included in all
+programs that make use of the GnuTLS library.
+
+
+File: gnutls.info, Node: Initialization, Next: Version check, Prev: Headers, Up: Preparation
+
+6.2.2 Initialization
+--------------------
+
+The GnuTLS library is initialized on load; prior to 3.3.0 was
+initialized by calling *note gnutls_global_init::(1). *note
+gnutls_global_init:: in versions after 3.3.0 is thread-safe (see *note
+Thread safety::).
+
+The initialization typically enables CPU-specific acceleration, performs
+any required precalculations needed, opens any required system devices
+(e.g., /dev/urandom on Linux) and initializes subsystems that could be
+used later.
+
+The resources allocated by the initialization process will be released
+on library deinitialization.
+
+Note that on certain systems file descriptors may be kept open by GnuTLS
+(e.g. /dev/urandom) on library load. Applications closing all unknown
+file descriptors must immediately call *note gnutls_global_init::, after
+that, to ensure they don't disrupt GnuTLS' operation.
+
+ ---------- Footnotes ----------
+
+ (1) The original behavior of requiring explicit initialization can
+obtained by setting the GNUTLS_NO_IMPLICIT_INIT environment variable to
+1, or by using the macro GNUTLS_SKIP_GLOBAL_INIT in a global section of
+your program -the latter works in systems with support for weak symbols
+only.
+
+
+File: gnutls.info, Node: Version check, Next: Building the source, Prev: Initialization, Up: Preparation
+
+6.2.3 Version check
+-------------------
+
+It is often desirable to check that the version of 'gnutls' used is
+indeed one which fits all requirements. Even with binary compatibility
+new features may have been introduced but due to problem with the
+dynamic linker an old version is actually used. So you may want to
+check that the version is okay right after program start-up. See the
+function *note gnutls_check_version::.
+
+On the other hand, it is often desirable to support more than one
+versions of the library. In that case you could utilize compile-time
+feature checks using the 'GNUTLS_VERSION_NUMBER' macro. For example, to
+conditionally add code for GnuTLS 3.2.1 or later, you may use:
+ #if GNUTLS_VERSION_NUMBER >= 0x030201
+ ...
+ #endif
+
+
+File: gnutls.info, Node: Building the source, Prev: Version check, Up: Preparation
+
+6.2.4 Building the source
+-------------------------
+
+If you want to compile a source file including the 'gnutls/gnutls.h'
+header file, you must make sure that the compiler can find it in the
+directory hierarchy. This is accomplished by adding the path to the
+directory in which the header file is located to the compilers include
+file search path (via the '-I' option).
+
+However, the path to the include file is determined at the time the
+source is configured. To solve this problem, the library uses the
+external package 'pkg-config' that knows the path to the include file
+and other configuration options. The options that need to be added to
+the compiler invocation at compile time are output by the '--cflags'
+option to 'pkg-config gnutls'. The following example shows how it can
+be used at the command line:
+
+ gcc -c foo.c `pkg-config gnutls --cflags`
+
+Adding the output of 'pkg-config gnutls --cflags' to the compilers
+command line will ensure that the compiler can find the
+'gnutls/gnutls.h' header file.
+
+A similar problem occurs when linking the program with the library.
+Again, the compiler has to find the library files. For this to work,
+the path to the library files has to be added to the library search path
+(via the '-L' option). For this, the option '--libs' to 'pkg-config
+gnutls' can be used. For convenience, this option also outputs all
+other options that are required to link the program with the library
+(for instance, the '-ltasn1' option). The example shows how to link
+'foo.o' with the library to a program 'foo'.
+
+ gcc -o foo foo.o `pkg-config gnutls --libs`
+
+Of course you can also combine both examples to a single command by
+specifying both options to 'pkg-config':
+
+ gcc -o foo foo.c `pkg-config gnutls --cflags --libs`
+
+When a program uses the GNU autoconf system, then the following line or
+similar can be used to detect the presence of GnuTLS.
+
+ PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.3.0])
+
+ AC_SUBST([LIBGNUTLS_CFLAGS])
+ AC_SUBST([LIBGNUTLS_LIBS])
+
+
+File: gnutls.info, Node: Session initialization, Next: Associating the credentials, Prev: Preparation, Up: How to use GnuTLS in applications
+
+6.3 Session initialization
+==========================
+
+In the previous sections we have discussed the global initialization
+required for GnuTLS as well as the initialization required for each
+authentication method's credentials (see *note Authentication::). In
+this section we elaborate on the TLS or DTLS session initiation. Each
+session is initialized using *note gnutls_init:: which among others is
+used to specify the type of the connection (server or client), and the
+underlying protocol type, i.e., datagram (UDP) or reliable (TCP).
+
+ -- Function: int gnutls_init (gnutls_session_t * SESSION, unsigned int
+ FLAGS)
+ SESSION: is a pointer to a 'gnutls_session_t' type.
+
+ FLAGS: indicate if this session is to be used for server or client.
+
+ This function initializes the provided session. Every session must
+ be initialized before use, and must be deinitialized after used by
+ calling 'gnutls_deinit()' .
+
+ 'flags' can be any combination of flags from 'gnutls_init_flags_t'
+ .
+
+ Note that since version 3.1.2 this function enables some common TLS
+ extensions such as session tickets and OCSP certificate status
+ request in client side by default. To prevent that use the
+ 'GNUTLS_NO_EXTENSIONS' flag.
+
+ *Returns:* 'GNUTLS_E_SUCCESS' on success, or an error code.
+
+'GNUTLS_SERVER'
+ Connection end is a server.
+'GNUTLS_CLIENT'
+ Connection end is a client.
+'GNUTLS_DATAGRAM'
+ Connection is datagram oriented (DTLS). Since 3.0.0.
+'GNUTLS_NONBLOCK'
+ Connection should not block. Since 3.0.0.
+'GNUTLS_NO_EXTENSIONS'
+ Do not enable any TLS extensions by default (since 3.1.2). As TLS
+ 1.2 and later require extensions this option is considered obsolete
+ and should not be used.
+'GNUTLS_NO_REPLAY_PROTECTION'
+ Disable any replay protection in DTLS. This must only be used if
+ replay protection is achieved using other means. Since 3.2.2.
+'GNUTLS_NO_SIGNAL'
+ In systems where SIGPIPE is delivered on send, it will be disabled.
+ That flag has effect in systems which support the MSG_NOSIGNAL
+ sockets flag (since 3.4.2).
+'GNUTLS_ALLOW_ID_CHANGE'
+ Allow the peer to replace its certificate, or change its ID during
+ a rehandshake. This change is often used in attacks and thus
+ prohibited by default. Since 3.5.0.
+'GNUTLS_ENABLE_FALSE_START'
+ Enable the TLS false start on client side if the negotiated
+ ciphersuites allow it. This will enable sending data prior to the
+ handshake being complete, and may introduce a risk of crypto
+ failure when combined with certain key exchanged; for that GnuTLS
+ may not enable that option in ciphersuites that are known to be not
+ safe for false start. Since 3.5.0.
+'GNUTLS_FORCE_CLIENT_CERT'
+ When in client side and only a single cert is specified, send that
+ certificate irrespective of the issuers expected by the server.
+ Since 3.5.0.
+'GNUTLS_NO_TICKETS'
+ Flag to indicate that the session should not use resumption with
+ session tickets.
+'GNUTLS_KEY_SHARE_TOP'
+ Generate key share for the first group which is enabled. For
+ example x25519. This option is the most performant for client
+ (less CPU spent generating keys), but if the server doesn't support
+ the advertized option it may result to more roundtrips needed to
+ discover the server's choice.
+'GNUTLS_KEY_SHARE_TOP2'
+ Generate key shares for the top-2 different groups which are
+ enabled. For example (ECDH + x25519). This is the default.
+'GNUTLS_KEY_SHARE_TOP3'
+ Generate key shares for the top-3 different groups which are
+ enabled. That is, as each group is associated with a key type (EC,
+ finite field, x25519), generate three keys using 'GNUTLS_PK_DH' ,
+ 'GNUTLS_PK_EC' , 'GNUTLS_PK_ECDH_X25519' if all of them are
+ enabled.
+'GNUTLS_POST_HANDSHAKE_AUTH'
+ Enable post handshake authentication for server and client. When
+ set and a server requests authentication after handshake
+ 'GNUTLS_E_REAUTH_REQUEST' will be returned by
+ 'gnutls_record_recv()' . A client should then call
+ 'gnutls_reauth()' to re-authenticate.
+'GNUTLS_NO_AUTO_REKEY'
+ Disable auto-rekeying under TLS1.3. If this option is not
+ specified gnutls will force a rekey after 2^24 records have been
+ sent.
+'GNUTLS_SAFE_PADDING_CHECK'
+ Flag to indicate that the TLS 1.3 padding check will be done in a
+ safe way which doesn't leak the pad size based on GnuTLS processing
+ time. This is of use to applications which hide the length of
+ transferred data via the TLS1.3 padding mechanism and are already
+ taking steps to hide the data processing time. This comes at a
+ performance penalty.
+'GNUTLS_ENABLE_EARLY_START'
+ Under TLS1.3 allow the server to return earlier than the full
+ handshake finish; similarly to false start the handshake will be
+ completed once data are received by the client, while the server is
+ able to transmit sooner. This is not enabled by default as it
+ could break certain existing server assumptions and use-cases.
+ Since 3.6.4.
+'GNUTLS_ENABLE_RAWPK'
+ Allows raw public-keys to be negotiated during the handshake.
+ Since 3.6.6.
+'GNUTLS_AUTO_REAUTH'
+ Enable transparent re-authentication in client side when the server
+ requests to. That is, reauthentication is handled within
+ 'gnutls_record_recv()' , and the 'GNUTLS_E_REHANDSHAKE' or
+ 'GNUTLS_E_REAUTH_REQUEST' are not returned. This must be enabled
+ with 'GNUTLS_POST_HANDSHAKE_AUTH' for TLS1.3. Enabling this flag
+ requires to restore interrupted calls to 'gnutls_record_recv()'
+ based on the output of 'gnutls_record_get_direction()' , since
+ 'gnutls_record_recv()' could be interrupted when sending when this
+ flag is enabled. Note this flag may not be used if you are using
+ the same session for sending and receiving in different threads.
+'GNUTLS_ENABLE_EARLY_DATA'
+ Under TLS1.3 allow the server to receive early data sent as part of
+ the initial ClientHello (0-RTT). This can also be used to
+ explicitly indicate that the client will send early data. This is
+ not enabled by default as early data has weaker security properties
+ than other data. Since 3.6.5.
+'GNUTLS_NO_AUTO_SEND_TICKET'
+ Under TLS1.3 disable auto-sending of session tickets during the
+ handshake.
+'GNUTLS_NO_END_OF_EARLY_DATA'
+ Under TLS1.3 suppress sending EndOfEarlyData message. Since 3.7.2.
+'GNUTLS_NO_TICKETS_TLS12'
+ Flag to indicate that the session should not use resumption with
+ session tickets. This flag only has effect if TLS 1.2 is used.
+
+
+Figure 6.2: The 'gnutls_init_flags_t' enumeration.
+
+After the session initialization details on the allowed ciphersuites and
+protocol versions should be set using the priority functions such as
+*note gnutls_priority_set:: and *note gnutls_priority_set_direct::. We
+elaborate on them in *note Priority Strings::. The credentials used for
+the key exchange method, such as certificates or usernames and passwords
+should also be associated with the session current session using *note
+gnutls_credentials_set::.
+
+ -- Function: int gnutls_credentials_set (gnutls_session_t SESSION,
+ gnutls_credentials_type_t TYPE, void * CRED)
+ SESSION: is a 'gnutls_session_t' type.
+
+ TYPE: is the type of the credentials
+
+ CRED: the credentials to set
+
+ Sets the needed credentials for the specified type. E.g.
+ username, password - or public and private keys etc. The 'cred'
+ parameter is a structure that depends on the specified type and on
+ the current session (client or server).
+
+ In order to minimize memory usage, and share credentials between
+ several threads gnutls keeps a pointer to cred, and not the whole
+ cred structure. Thus you will have to keep the structure allocated
+ until you call 'gnutls_deinit()' .
+
+ For 'GNUTLS_CRD_ANON' , 'cred' should be
+ 'gnutls_anon_client_credentials_t' in case of a client. In case of
+ a server it should be 'gnutls_anon_server_credentials_t' .
+
+ For 'GNUTLS_CRD_SRP' , 'cred' should be
+ 'gnutls_srp_client_credentials_t' in case of a client, and
+ 'gnutls_srp_server_credentials_t' , in case of a server.
+
+ For 'GNUTLS_CRD_CERTIFICATE' , 'cred' should be
+ 'gnutls_certificate_credentials_t' .
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise a negative error code is returned.
+
+
+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::
+* Raw public-key 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 and 'KX_RSA', 'CRD_CERTIFICATE''CRD_CERTIFICATE'
+Raw public-key 'KX_DHE_RSA',
+ 'KX_DHE_DSS',
+ 'KX_ECDHE_RSA',
+ 'KX_ECDHE_ECDSA'
+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: Raw public-key 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.
+
+In order to use certificate credentials one must first initialize a
+credentials structure of type 'gnutls_certificate_credentials_t'. After
+use this structure must be freed. This can be done with the following
+functions.
+
+'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_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_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)'
+
+It is recommended to use the higher level functions such as *note
+gnutls_certificate_set_x509_key_file2:: which accept not only file names
+but URLs that specify objects stored in token, or system certificates
+and keys (see *note Application-specific keys::). For these cases,
+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.
+
+ -- 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' type.
+
+ 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' type.
+
+ NAMES: is an array of DNS names belonging to the public-key (NULL
+ if none)
+
+ NAMES_SIZE: holds the size of the names list
+
+ PCERT_LIST: contains a certificate list (chain) or raw public-key
+
+ PCERT_LIST_SIZE: holds the size of the certificate list
+
+ KEY: is a 'gnutls_privkey_t' key corresponding to the first
+ public-key in pcert_list
+
+ This function sets a public/private key pair in the
+ gnutls_certificate_credentials_t type. The given public key may be
+ encapsulated in a certificate or can be given as a raw key. This
+ function may be called more than once, in case multiple key pairs
+ exist for the server. For clients that want to send more than
+ their own end- entity certificate (e.g., also an intermediate CA
+ cert), the full certificate chain must be provided in 'pcert_list'
+ .
+
+ Note that the 'key' will become part of the credentials structure
+ and must not be deallocated. It will be automatically deallocated
+ when the 'res' structure is deinitialized.
+
+ If this function fails, the 'res' structure is at an undefined
+ state and it must not be reused to load other keys or certificates.
+
+ Note that, this function by default returns zero on success and a
+ negative value on error. Since 3.5.6, when the flag
+ 'GNUTLS_CERTIFICATE_API_V2' is set using
+ 'gnutls_certificate_set_flags()' it returns an index (greater or
+ equal to zero). That index can be used for other functions to
+ refer to the added key-pair.
+
+ Since GnuTLS 3.6.6 this function also handles raw public keys.
+
+ *Returns:* On success this functions returns zero, and otherwise a
+ negative value on error (see above for modifying that behavior).
+
+ *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)'
+'VOID *note gnutls_certificate_set_retrieve_function3:: (gnutls_certificate_credentials_t CRED, gnutls_certificate_retrieve_function3 * FUNC)'
+'INT *note gnutls_sign_algorithm_get_requested:: (gnutls_session_t SESSION, size_t INDX, gnutls_sign_algorithm_t * ALGO)'
+
+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_x509_raw:: (gnutls_pcert_st * PCERT, const gnutls_datum_t * CERT, gnutls_x509_crt_fmt_t FORMAT, 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 by *note gnutls_certificate_server_set_request::.
+The request contains a list of the by the server accepted certificate
+signers. This list is constructed using the trusted certificate
+authorities of the server. In cases where the server supports a large
+number of certificate authorities it makes sense not to advertise all of
+the names to save bandwidth. That can be controlled using the function
+*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' type.
+
+ REQ: is one of GNUTLS_CERT_REQUEST, GNUTLS_CERT_REQUIRE,
+ GNUTLS_CERT_IGNORE
+
+ 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 the
+ 'GNUTLS_E_NO_CERTIFICATE_FOUND' 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. Invoking the function
+ with 'req' GNUTLS_CERT_IGNORE has the same effect.
+
+ -- Function: void gnutls_certificate_send_x509_rdn_sequence
+ (gnutls_session_t SESSION, int STATUS)
+ SESSION: a 'gnutls_session_t' type.
+
+ 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.
+
+On the client side, it needs to set its certificates on the credentials
+structure, similarly to server side from a file, or via a callback.
+Once the certificates are available in the credentials structure, the
+client will send them if during the handshake the server requests a
+certificate signed by the issuer of its CA.
+
+In the case a single certificate is available and the server does not
+specify a signer's list, then that certificate is always sent. It is,
+however possible, to send a certificate even when the advertised CA list
+by the server contains CAs other than its signer. That can be achieved
+using the 'GNUTLS_FORCE_CLIENT_CERT' flag in *note gnutls_init::.
+
+'INT *note gnutls_certificate_set_x509_key_file:: (gnutls_certificate_credentials_t RES, const char * CERTFILE, const char * KEYFILE, gnutls_x509_crt_fmt_t TYPE)'
+'INT *note gnutls_certificate_set_x509_simple_pkcs12_file:: (gnutls_certificate_credentials_t RES, const char * PKCS12FILE, gnutls_x509_crt_fmt_t TYPE, const char * PASSWORD)'
+'VOID *note gnutls_certificate_set_retrieve_function2:: (gnutls_certificate_credentials_t CRED, gnutls_certificate_retrieve_function2 * FUNC)'
+
+Client or server certificate verification
+.........................................
+
+Certificate verification is possible by loading the trusted authorities
+into the credentials structure by using the following functions,
+applicable to X.509 certificates. In modern systems it is recommended
+to utilize *note gnutls_certificate_set_x509_system_trust:: which will
+load the trusted authorities from the system store.
+
+ -- Function: int gnutls_certificate_set_x509_system_trust
+ (gnutls_certificate_credentials_t CRED)
+ CRED: is a 'gnutls_certificate_credentials_t' type.
+
+ This function adds the system's default trusted CAs in order to
+ verify client or server certificates.
+
+ In the case the system is currently unsupported
+ 'GNUTLS_E_UNIMPLEMENTED_FEATURE' is returned.
+
+ *Returns:* the number of certificates processed or a negative error
+ code on error.
+
+ *Since:* 3.0.20
+'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_x509_trust_dir:: (gnutls_certificate_credentials_t CRED, const char * CA_DIR, gnutls_x509_crt_fmt_t TYPE)'
+
+The peer's certificate will be automatically verified if *note
+gnutls_session_set_verify_cert:: is called prior to handshake.
+
+Alternatively, one must set a callback function during the handshake
+using *note gnutls_certificate_set_verify_function::, which will verify
+the peer's certificate once received. The verification should happen
+using *note gnutls_certificate_verify_peers3:: within the callback. It
+will verify the certificate's signature and the owner of the
+certificate. That will provide a brief verification output. If a
+detailed output is required one should call *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::.
+
+In both the automatic and the manual cases, the verification status
+returned can be printed using *note
+gnutls_certificate_verification_status_print::.
+
+ -- Function: void gnutls_session_set_verify_cert (gnutls_session_t
+ SESSION, const char * HOSTNAME, unsigned FLAGS)
+ SESSION: is a gnutls session
+
+ HOSTNAME: is the expected name of the peer; may be 'NULL'
+
+ FLAGS: flags for certificate verification -
+ 'gnutls_certificate_verify_flags'
+
+ This function instructs GnuTLS to verify the peer's certificate
+ using the provided hostname. If the verification fails the
+ handshake will also fail with
+ 'GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR' . In that case the
+ verification result can be obtained using
+ 'gnutls_session_get_verify_cert_status()' .
+
+ The 'hostname' pointer provided must remain valid for the lifetime
+ of the session. More precisely it should be available during any
+ subsequent handshakes. If no hostname is provided, no hostname
+ verification will be performed. For a more advanced verification
+ function check 'gnutls_session_set_verify_cert2()' .
+
+ If 'flags' is provided which contain a profile, this function
+ should be called after any session priority setting functions.
+
+ The 'gnutls_session_set_verify_cert()' function is intended to be
+ used by TLS clients to verify the server's certificate.
+
+ *Since:* 3.4.6
+
+'INT *note gnutls_certificate_verify_peers3:: (gnutls_session_t SESSION, const char * HOSTNAME, unsigned int * STATUS)'
+'VOID *note gnutls_certificate_set_verify_function:: (gnutls_certificate_credentials_t CRED, gnutls_certificate_verify_function * FUNC)'
+
+Note that when using raw public-keys verification will not work because
+there is no corresponding certificate body belonging to the raw key that
+can be verified. In that case the *note
+gnutls_certificate_verify_peers:: family of functions will return a
+GNUTLS_E_INVALID_REQUEST error code. For authenticating raw public-keys
+one must use an out-of-band mechanism, e.g. by comparing hashes or
+using trust on first use (see *note Verifying a certificate using trust
+on first use authentication::).
+
+
+File: gnutls.info, Node: Raw public-key credentials, Next: SRP credentials, Prev: Certificate credentials, Up: Associating the credentials
+
+6.4.2 Raw public-keys
+---------------------
+
+As of version 3.6.6 GnuTLS supports *note Raw public-keys::. With raw
+public-keys only the public-key part (that is normally embedded in a
+certificate) is transmitted to the peer. In order to load a raw
+public-key and its corresponding private key in a credentials structure
+one can use the following functions.
+
+'INT *note 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)'
+'INT *note gnutls_certificate_set_rawpk_key_mem:: (gnutls_certificate_credentials_t CRED, const gnutls_datum_t* SPKI, const gnutls_datum_t* PKEY, gnutls_x509_crt_fmt_t FORMAT, const char* PASS, unsigned int KEY_USAGE, const char ** NAMES, unsigned int NAMES_LENGTH, unsigned int FLAGS)'
+'INT *note gnutls_certificate_set_rawpk_key_file:: (gnutls_certificate_credentials_t CRED, const char* RAWPKFILE, const char* PRIVKEYFILE, gnutls_x509_crt_fmt_t FORMAT, const char * PASS, unsigned int KEY_USAGE, const char ** NAMES, unsigned int NAMES_LENGTH, unsigned int PRIVKEY_FLAGS, unsigned int PKCS11_FLAGS)'
+
+
+File: gnutls.info, Node: SRP credentials, Next: PSK credentials, Prev: Raw public-key credentials, Up: Associating the credentials
+
+6.4.3 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' type.
+
+ 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()' .
+
+ The 'username' should be an ASCII string or UTF-8 string. In case
+ of a UTF-8 string it is recommended to be following the PRECIS
+ framework for usernames (rfc8265). The password can be in ASCII
+ format, or normalized using 'gnutls_utf8_password_normalize()' .
+
+ 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' type.
+
+ 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' type. 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' type.
+
+ 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.4 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' type.
+
+ 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()' . The 'username' should be an ASCII string or
+ UTF-8 string. In case of a UTF-8 string it is recommended to be
+ following the PRECIS framework for usernames (rfc8265).
+
+ 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' type.
+
+ PASSWORD_FILE: is the PSK password file (passwd.psk)
+
+ This function sets the password file, in a
+ 'gnutls_psk_server_credentials_t' type. This password file holds
+ usernames and keys and will be used for PSK authentication.
+
+ Each entry in the file consists of a username, followed by a colon
+ (':') and a hex-encoded key. If the username contains a colon or
+ any other special character, it can be hex-encoded preceded by a
+ '#'.
+
+ *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.5 Anonymous
+---------------
+
+The key exchange methods for anonymous authentication since GnuTLS 3.6.0
+will utilize the RFC7919 parameters, unless explicit parameters have
+been provided and associated with an anonymous credentials structure.
+Check *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 FD)'
+'VOID *note gnutls_transport_set_int2:: (gnutls_session_t SESSION, int RECV_FD, int SEND_FD)'
+
+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' type.
+
+ 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' type.
+
+ 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' type.
+
+ 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' type.
+
+ 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. The
+ special value 'GNUTLS_INDEFINITE_TIMEOUT' indicates that the
+ callback should wait indefinitely for data.
+
+ 'gnutls_pull_timeout_func' is of the form, int
+ (*gnutls_pull_timeout_func)(gnutls_transport_ptr_t, unsigned int
+ ms);
+
+ This callback is necessary when 'gnutls_handshake_set_timeout()' or
+ 'gnutls_record_set_timeout()' are set, under TLS1.3 and for
+ enforcing the DTLS mode timeouts when in blocking mode.
+
+ For compatibility with future GnuTLS versions this callback must be
+ set when a custom pull function is registered. The callback will
+ not be used when the session is in TLS mode with non-blocking
+ sockets. That is, when 'GNUTLS_NONBLOCK' is specified for a TLS
+ session in 'gnutls_init()' .
+
+ The helper function 'gnutls_system_recv_timeout()' is provided to
+ simplify writing callbacks.
+
+ *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' type.
+
+ 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).
+
+ This function is unreliable if you are using the same 'session' in
+ different threads for sending and receiving.
+
+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' type.
+
+ 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. The
+ special value 'GNUTLS_INDEFINITE_TIMEOUT' indicates that the
+ callback should wait indefinitely for data.
+
+ 'gnutls_pull_timeout_func' is of the form, int
+ (*gnutls_pull_timeout_func)(gnutls_transport_ptr_t, unsigned int
+ ms);
+
+ This callback is necessary when 'gnutls_handshake_set_timeout()' or
+ 'gnutls_record_set_timeout()' are set, under TLS1.3 and for
+ enforcing the DTLS mode timeouts when in blocking mode.
+
+ For compatibility with future GnuTLS versions this callback must be
+ set when a custom pull function is registered. The callback will
+ not be used when the session is in TLS mode with non-blocking
+ sockets. That is, when 'GNUTLS_NONBLOCK' is specified for a TLS
+ session in 'gnutls_init()' .
+
+ The helper function 'gnutls_system_recv_timeout()' is provided to
+ simplify writing callbacks.
+
+ *Since:* 3.0
+
+ -- Function: unsigned int gnutls_dtls_get_timeout (gnutls_session_t
+ SESSION)
+ SESSION: is a 'gnutls_session_t' type.
+
+ 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::
+* Reducing round-trips::
+* Zero-roundtrip mode::
+* Anti-replay protection::
+* DTLS sessions::
+* DTLS and SCTP::
+
+
+File: gnutls.info, Node: Asynchronous operation, Next: Reducing round-trips, 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.,
+return -1 and set errno to 'EAGAIN'. Since, during a TLS protocol
+session GnuTLS does not block except for network interaction, the non
+blocking 'EAGAIN' errno will be propagated and GnuTLS functions will
+return the 'GNUTLS_E_AGAIN' error code. Such calls can be resumed the
+same way as a system call would. The only exception is *note
+gnutls_record_send::, which if interrupted subsequent calls need not to
+include the data to be sent (can be called with NULL argument).
+
+When using the 'poll' or 'select' system calls though, one should
+remember that they only apply to the kernel sockets API. To check for
+any available buffered data in a GnuTLS session, utilize *note
+gnutls_record_check_pending::, either before the 'poll' system call, or
+after a call to *note gnutls_record_recv::. Data queued by *note
+gnutls_record_send:: (when interrupted) can be discarded using *note
+gnutls_record_discard_queued::.
+
+An example of GnuTLS' usage with asynchronous operation can be found in
+'doc/examples/tlsproxy'.
+
+The following paragraphs describe the detailed requirements for
+non-blocking operation when using the TLS or DTLS protocols.
+
+6.5.1.1 TLS protocol
+....................
+
+There are no special requirements for the TLS protocol operation in
+non-blocking mode if a non-blocking socket is used.
+
+It is recommended, however, for future compatibility, when in
+non-blocking mode, to call the *note gnutls_init:: function with the
+'GNUTLS_NONBLOCK' flag set (see *note Session initialization::).
+
+6.5.1.2 Datagram TLS protocol
+.............................
+
+When in non-blocking mode the function, the *note gnutls_init:: function
+must be called with the 'GNUTLS_NONBLOCK' flag set (see *note Session
+initialization::).
+
+In contrast with the TLS protocol, the pull timeout function is
+required, but will only be called with a timeout of zero. In that case
+it should indicate whether there are data to be received or not. When
+not using the default pull function, then *note
+gnutls_transport_set_pull_timeout_function:: should be called.
+
+Although in the TLS protocol implementation each call to receive or send
+function implies to restoring the same function that was interrupted, in
+the DTLS protocol this requirement isn't true. There are cases where a
+retransmission is required, which are indicated by a received message
+and thus *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' type.
+
+ This function is useful to determine whether a GnuTLS function was
+ interrupted while sending or receiving, so that 'select()' or
+ 'poll()' may be called appropriately.
+
+ It 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 and returned
+ 'GNUTLS_E_INTERRUPTED' or 'GNUTLS_E_AGAIN' . After such an
+ interrupt applications may call 'select()' or 'poll()' before
+ restoring the interrupted GnuTLS function.
+
+ This function's output is unreliable if you are using the same
+ 'session' in different threads for sending and receiving.
+
+ *Returns:* 0 if interrupted while trying to read data, or 1 while
+ trying to write data.
+
+When calling *note gnutls_handshake:: through a multi-plexer, to be able
+to handle properly the DTLS handshake retransmission timers, the
+function *note gnutls_dtls_get_timeout:: should be used to estimate when
+to call *note gnutls_handshake:: if no data have been received.
+
+
+File: gnutls.info, Node: Reducing round-trips, Next: Zero-roundtrip mode, Prev: Asynchronous operation, Up: Setting up the transport layer
+
+6.5.2 Reducing round-trips
+--------------------------
+
+The full TLS 1.2 handshake requires 2 round-trips to complete, and when
+combined with TCP's SYN and SYN-ACK negotiation it extends to 3 full
+round-trips. While, TLS 1.3 reduces that to two round-trips when under
+TCP, it still adds considerable latency, making the protocol unsuitable
+for certain applications.
+
+To optimize the handshake latency, in client side, it is possible to
+take advantage of the TCP fast open [*note RFC7413::] mechanism on
+operating systems that support it. That can be done either by manually
+crafting the push and pull callbacks, or by utilizing *note
+gnutls_transport_set_fastopen::. In that case the initial TCP handshake
+is eliminated, reducing the TLS 1.2 handshake round-trip to 2, and the
+TLS 1.3 handshake to a single round-trip. Note, that when this function
+is used, any connection failures will be reported during the *note
+gnutls_handshake:: function call with error code 'GNUTLS_E_PUSH_ERROR'.
+
+ -- Function: void gnutls_transport_set_fastopen (gnutls_session_t
+ SESSION, int FD, struct sockaddr * CONNECT_ADDR, socklen_t
+ CONNECT_ADDRLEN, unsigned int FLAGS)
+ SESSION: is a 'gnutls_session_t' type.
+
+ FD: is the session's socket descriptor
+
+ CONNECT_ADDR: is the address we want to connect to
+
+ CONNECT_ADDRLEN: is the length of 'connect_addr'
+
+ FLAGS: must be zero
+
+ Enables TCP Fast Open (TFO) for the specified TLS client session.
+ That means that TCP connection establishment and the transmission
+ of the first TLS client hello packet are combined. The peer's
+ address must be specified in 'connect_addr' and 'connect_addrlen' ,
+ and the socket specified by 'fd' should not be connected.
+
+ TFO only works for TCP sockets of type AF_INET and AF_INET6. If
+ the OS doesn't support TCP fast open this function will result to
+ gnutls using 'connect()' transparently during the first write.
+
+ *Note:* This function overrides all the transport callback
+ functions. If this is undesirable, TCP Fast Open must be
+ implemented on the user callback functions without calling this
+ function. When using this function, transport callbacks must not
+ be set, and 'gnutls_transport_set_ptr()' or
+ 'gnutls_transport_set_int()' must not be called.
+
+ On GNU/Linux TFO has to be enabled at the system layer, that is in
+ /proc/sys/net/ipv4/tcp_fastopen, bit 0 has to be set.
+
+ This function has no effect on server sessions.
+
+ *Since:* 3.5.3
+
+When restricted to TLS 1.2, and non-resumed sessions, it is possible to
+further reduce the round-trips to a single one by taking advantage of
+the *note False Start:: TLS extension. This can be enabled by setting
+the GNUTLS_ENABLE_FALSE_START flag on *note gnutls_init::.
+
+Under TLS 1.3, the server side can start transmitting before the
+handshake is complete (i.e., while the client Finished message is still
+in flight), when no client certificate authentication is requested.
+This, unlike false start, is part of protocol design with no known
+security implications. It can be enabled by setting the
+GNUTLS_ENABLE_EARLY_START on *note gnutls_init::, and the *note
+gnutls_handshake:: function will return early, allowing the server to
+send data earlier.
+
+
+File: gnutls.info, Node: Zero-roundtrip mode, Next: Anti-replay protection, Prev: Reducing round-trips, Up: Setting up the transport layer
+
+6.5.3 Zero-roundtrip mode
+-------------------------
+
+Under TLS 1.3, when the client has already connected to the server and
+is resuming a session, it can start transmitting application data during
+handshake. This is called zero round-trip time (0-RTT) mode, and the
+application data sent in this mode is called early data. The client can
+send early data with *note gnutls_record_send_early_data::. The client
+should call this function before calling *note gnutls_handshake:: and
+after calling *note gnutls_session_set_data::.
+
+Note, however, that early data has weaker security properties than
+normal application data sent after handshake, such as lack of forward
+secrecy, no guarantees of non-replay between connections. Thus it is
+disabled on the server side by default. To enable it, the server needs
+to:
+ 1. Set GNUTLS_ENABLE_EARLY_DATA on *note gnutls_init::. Note that
+ this option only has effect on server.
+
+ 2. Enable anti-replay measure. See *note Anti-replay protection:: for
+ the details.
+
+The server caches the received early data until it is read. To set the
+maximum amount of data to be stored in the cache, use *note
+gnutls_record_set_max_early_data_size::. After receiving the
+EndOfEarlyData handshake message, the server can start retrieving the
+received data with *note gnutls_record_recv_early_data::. You can call
+the function either after the handshake is complete, or through a
+handshake hook (*note gnutls_handshake_set_hook_function::).
+
+When sending early data, the client should respect the maximum amount of
+early data, which may have been previously advertised by the server. It
+can be checked using *note gnutls_record_get_max_early_data_size::,
+right after calling *note gnutls_session_set_data::.
+
+After sending early data, to check whether the sent early data was
+accepted by the server, use *note gnutls_session_get_flags:: and compare
+the result with GNUTLS_SFLAGS_EARLY_DATA. Similarly, on the server
+side, the same function and flag can be used to check whether it has
+actually accepted early data.
+
+
+File: gnutls.info, Node: Anti-replay protection, Next: DTLS sessions, Prev: Zero-roundtrip mode, Up: Setting up the transport layer
+
+6.5.4 Anti-replay protection
+----------------------------
+
+When 0-RTT mode is used, the server must protect itself from replay
+attacks, where adversary client reuses duplicate session ticket to send
+early data, before the server authenticates the client.
+
+GnuTLS provides a simple mechanism against replay attacks, following the
+method called ClientHello recording. When a session ticket is accepted,
+the server checks if the ClientHello message has been already seen. If
+there is a duplicate, the server rejects early data.
+
+The problem of this approach is that the number of recorded messages
+grows indefinitely. To prevent that, the server can limit the recording
+to a certain time window, which can be configured with *note
+gnutls_anti_replay_set_window::.
+
+The anti-replay mechanism shall be globally initialized with *note
+gnutls_anti_replay_init::, and then attached to a session using *note
+gnutls_anti_replay_enable::. It can be deinitialized with *note
+gnutls_anti_replay_deinit::.
+
+The server must also set up a database back-end to store ClientHello
+messages. That can be achieved using *note
+gnutls_anti_replay_set_add_function:: and *note
+gnutls_anti_replay_set_ptr::.
+
+Note that, if the back-end stores arbitrary number of ClientHello, it
+needs to periodically clean up the stored entries based on the time
+window set with *note gnutls_anti_replay_set_window::. The cleanup can
+be implemented by iterating through the database entries and calling
+*note gnutls_db_check_entry_expire_time::. This is similar to session
+database cleanup used by TLS1.2 sessions.
+
+The full set up of the server using early data would be like the
+following example:
+ #define MAX_EARLY_DATA_SIZE 16384
+
+ static int
+ db_add_func(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
+ {
+ /* Return GNUTLS_E_DB_ENTRY_EXISTS, if KEY is found in the database.
+ * Otherwise, store it and return 0.
+ */
+ }
+
+ static int
+ handshake_hook_func(gnutls_session_t session, unsigned int htype,
+ unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
+ {
+ int ret;
+ char buf[MAX_EARLY_DATA_SIZE];
+
+ assert(htype == GNUTLS_HANDSHAKE_END_OF_EARLY_DATA);
+ assert(when == GNUTLS_HOOK_POST);
+
+ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_EARLY_DATA) {
+ ret = gnutls_record_recv_early_data(session, buf, sizeof(buf));
+ assert(ret >= 0);
+ }
+
+ return ret;
+ }
+
+ int main()
+ {
+ ...
+ /* Initialize anti-replay measure, which can be shared
+ * among multiple sessions.
+ */
+ gnutls_anti_replay_init(&anti_replay);
+
+ /* Set the database back-end function for the anti-replay data. */
+ gnutls_anti_replay_set_add_function(anti_replay, db_add_func);
+ gnutls_anti_replay_set_ptr(anti_replay, NULL);
+
+ ...
+
+ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_ENABLE_EARLY_DATA);
+ gnutls_record_set_max_early_data_size(server, MAX_EARLY_DATA_SIZE);
+
+ ...
+
+ /* Set the anti-replay measure to the session.
+ */
+ gnutls_anti_replay_enable(server, anti_replay);
+ ...
+
+ /* Retrieve early data in a handshake hook;
+ * you can also do that after handshake.
+ */
+ gnutls_handshake_set_hook_function(server, GNUTLS_HANDSHAKE_END_OF_EARLY_DATA,
+ GNUTLS_HOOK_POST, handshake_hook_func);
+ ...
+ }
+
+
+File: gnutls.info, Node: DTLS sessions, Next: DTLS and SCTP, Prev: Anti-replay protection, Up: Setting up the transport layer
+
+6.5.5 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 [*note
+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: DTLS and SCTP, Prev: DTLS sessions, Up: Setting up the transport layer
+
+6.5.6 DTLS and SCTP
+-------------------
+
+Although DTLS can run under any reliable or unreliable layer, there are
+special requirements for SCTP according to [*note RFC6083::]. We
+summarize the most important below, however for a full treatment we
+refer to [*note RFC6083::].
+
+ * The MTU set via *note gnutls_dtls_set_mtu:: must be 2^14.
+ * Replay detection must be disabled; use the flag
+ 'GNUTLS_NO_REPLAY_PROTECTION' with *note gnutls_init::.
+ * Retransmission of messages must be disabled; use *note
+ gnutls_dtls_set_timeouts:: with a retransmission timeout larger
+ than the total.
+ * Handshake, Alert and ChangeCipherSpec messages must be sent over
+ stream 0 with unlimited reliability and with the ordered delivery
+ feature.
+ * During a rehandshake, the caching of messages with unknown epoch is
+ not handled by GnuTLS; this must be implemented in a special pull
+ function.
+
+
+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' type.
+
+ This function performs the handshake of the TLS/SSL protocol, and
+ initializes the TLS session parameters.
+
+ The non-fatal errors expected by this function are:
+ 'GNUTLS_E_INTERRUPTED' , 'GNUTLS_E_AGAIN' ,
+ 'GNUTLS_E_WARNING_ALERT_RECEIVED' . When this function is called
+ for re-handshake under TLS 1.2 or earlier, the non-fatal error code
+ 'GNUTLS_E_GOT_APPLICATION_DATA' may also be returned.
+
+ The former two interrupt the handshake procedure due to the
+ transport layer being interrupted, and the latter because of a
+ "warning" alert that was sent by the peer (it is always a good idea
+ to check any received alerts). On these non-fatal 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.
+
+ When this function is called by a server after a rehandshake
+ request under TLS 1.2 or earlier the
+ 'GNUTLS_E_GOT_APPLICATION_DATA' error code indicates that some data
+ were pending prior to peer initiating the handshake. Under TLS 1.3
+ this function when called after a successful handshake, is a no-op
+ and always succeeds in server side; in client side this function is
+ equivalent to 'gnutls_session_key_update()' with 'GNUTLS_KU_PEER'
+ flag.
+
+ This function handles both full and abbreviated TLS handshakes
+ (resumption). For abbreviated handshakes, in client side, the
+ 'gnutls_session_set_data()' should be called prior to this function
+ to set parameters from a previous session. In server side,
+ resumption is handled by either setting a DB back-end, or setting
+ up keys for session tickets.
+
+ *Returns:* 'GNUTLS_E_SUCCESS' on a successful handshake, otherwise
+ a negative error code.
+
+ -- Function: void gnutls_handshake_set_timeout (gnutls_session_t
+ SESSION, unsigned int MS)
+ SESSION: is a 'gnutls_session_t' type.
+
+ MS: is a timeout value in milliseconds
+
+ This function sets the timeout for the TLS 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.
+ For the DTLS protocol, the more detailed
+ 'gnutls_dtls_set_timeouts()' is provided.
+
+ This function requires to set a pull timeout callback. See
+ 'gnutls_transport_set_pull_timeout_function()' .
+
+ *Since:* 3.1.0
+
+In GnuTLS 3.5.0 and later it is recommended to use *note
+gnutls_session_set_verify_cert:: for the handshake process to ensure the
+verification of the peer's identity. That will verify the peer's
+certificate, against the trusted CA store while accounting for stapled
+OCSP responses during the handshake; any error will be returned as a
+handshake error.
+
+In older GnuTLS versions it is required to verify the peer's certificate
+during the handshake by setting a callback with *note
+gnutls_certificate_set_verify_function::, and then using *note
+gnutls_certificate_verify_peers3:: from it. See *note Certificate
+authentication:: for more information.
+
+'VOID *note gnutls_session_set_verify_cert:: (gnutls_session_t SESSION, const char * HOSTNAME, unsigned FLAGS)'
+'INT *note gnutls_certificate_verify_peers3:: (gnutls_session_t SESSION, const char * HOSTNAME, 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' type.
+
+ 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, or provide a 'NULL' pointer for
+ 'data' and 0 for 'data_size' , in order to write the same data as
+ before. If you wish to discard the previous data instead of
+ retrying, you must call 'gnutls_record_discard_queued()' before
+ calling this function with different parameters. Note that the
+ latter works only on special transports (e.g., UDP). 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' type.
+
+ 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 the peer requests a
+ renegotiation, the caller will receive an error code of
+ 'GNUTLS_E_REHANDSHAKE' . In case of a client, 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. A
+ server receiving this error code can only initiate a new handshake
+ or terminate the session.
+
+ If 'EINTR' is returned by the internal pull 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()' .
+
+ *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' type.
+
+ 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
+'poll', i.e., *note gnutls_record_check_pending:: reports no data to be
+read, 'poll' 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' type.
+
+ 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' type.
+
+ 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' type.
+
+ 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 preferable 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' type.
+
+ 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' type.
+
+ 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' type.
+
+ 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' type.
+
+ 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 ('GNUTLS_A_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
+=====================
+
+How to use Priority Strings
+---------------------------
+
+The GnuTLS priority strings specify the TLS session's handshake
+algorithms and options in a compact, easy-to-use format. These strings
+are intended as a user-specified override of the library defaults.
+
+That is, we recommend applications using the default settings (c.f.
+*note gnutls_set_default_priority:: or *note
+gnutls_set_default_priority_append::), and provide the user with access
+to priority strings for overriding the default behavior, on
+configuration files, or other UI. Following such a principle, makes the
+GnuTLS library as the default settings provider. That is necessary and
+a good practice, because TLS protocol hardening and phasing out of
+legacy algorithms, is easier to coordinate when happens in a single
+library.
+
+'INT *note gnutls_set_default_priority:: (gnutls_session_t SESSION)'
+'INT *note gnutls_set_default_priority_append:: (gnutls_session_t SESSION, const char * ADD_PRIO, const char ** ERR_POS, unsigned FLAGS)'
+'INT *note gnutls_priority_set_direct:: (gnutls_session_t SESSION, const char * PRIORITIES, const char ** ERR_POS)'
+
+The priority string translation to the internal GnuTLS form requires
+processing and the generated internal form also occupies some memory.
+For that, it is recommended to do that processing once in server side,
+and share the generated data across sessions. The following functions
+allow the generation of a "priority cache" and the sharing of it across
+sessions.
+
+'INT *note gnutls_priority_init2:: (gnutls_priority_t * PRIORITY_CACHE, const char * PRIORITIES, const char ** ERR_POS, unsigned FLAGS)'
+'INT *note gnutls_priority_init:: (gnutls_priority_t * PRIORITY_CACHE, const char * PRIORITIES, const char ** ERR_POS)'
+'INT *note gnutls_priority_set:: (gnutls_session_t SESSION, gnutls_priority_t PRIORITY)'
+'VOID *note gnutls_priority_deinit:: (gnutls_priority_t PRIORITY_CACHE)'
+
+Using Priority Strings
+----------------------
+
+A priority string 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).
+
+Keyword Description
+------------------------------------------------------------------
+@KEYWORD Means that a compile-time specified system
+ configuration file (see
+ *note System-wide configuration of the library::)
+ will be used to expand the provided keyword.
+ That is used to impose system-specific policies.
+ It may be followed by additional options that
+ will be appended to the system string (e.g.,
+ "@SYSTEM:+SRP"). The system file should have the
+ format 'KEYWORD=VALUE', e.g.,
+ 'SYSTEM=NORMAL:+ARCFOUR-128'.
+
+ Since version 3.5.1 it is allowed to specify
+ fallback keywords such as @KEYWORD1,@KEYWORD2,
+ and the first valid keyword will be used.
+
+PERFORMANCE All the known to be secure ciphersuites are
+ enabled, limited to 128 bit ciphers and sorted
+ by terms of speed performance. The message
+ authenticity security level is of 64 bits or
+ more, and the certificate verification profile
+ is set to GNUTLS_PROFILE_LOW (80-bits).
+
+NORMAL Means all the known to be secure ciphersuites.
+ The ciphers are sorted by security margin,
+ although the 256-bit ciphers are included as a
+ fallback only. The message authenticity
+ security level is of 64 bits or more, and the
+ certificate verification profile is set to
+ GNUTLS_PROFILE_LOW (80-bits).
+
+ This priority string implicitly enables ECDHE
+ and DHE. The ECDHE ciphersuites are placed first
+ in the priority order, but due to compatibility
+ issues with the DHE ciphersuites they are placed
+ last in the priority order, after the plain RSA
+ ciphersuites.
+
+LEGACY This sets the NORMAL settings that were used for
+ GnuTLS 3.2.x or earlier. There is no
+ verification profile set, and the allowed DH
+ primes are considered weak today (but are often
+ used by misconfigured servers).
+
+PFS Means all the known to be secure ciphersuites
+ that support perfect forward secrecy (ECDHE and
+ DHE). The ciphers are sorted by security margin,
+ although the 256-bit ciphers are included as a
+ fallback only. The message authenticity
+ security level is of 80 bits or more, and the
+ certificate verification profile is set to
+ GNUTLS_PROFILE_LOW (80-bits). This option is
+ available since 3.2.4 or later.
+
+SECURE128 Means all known to be secure ciphersuites that
+ offer a security level 128-bit or more. The
+ message authenticity security level is of 80
+ bits or more, and the certificate verification
+ profile is set to GNUTLS_PROFILE_LOW (80-bits).
+
+SECURE192 Means all the known to be secure ciphersuites
+ that offer a security level 192-bit or more.
+ The message authenticity security level is of
+ 128 bits or more, and the certificate
+ verification profile is set to
+ GNUTLS_PROFILE_HIGH (128-bits).
+
+SECURE256 Currently alias for SECURE192. This option,
+ will enable ciphers which use a 256-bit key but,
+ due to limitations of the TLS protocol, the
+ overall security level will be 192-bits (the
+ security level depends on more factors than
+ cipher key size).
+
+SUITEB128 Means all the NSA Suite B cryptography (RFC5430)
+ ciphersuites with an 128 bit security level, as
+ well as the enabling of the corresponding
+ verification profile.
+
+SUITEB192 Means all the NSA Suite B cryptography (RFC5430)
+ ciphersuites with an 192 bit security level, as
+ well as the enabling of the corresponding
+ verification profile.
+
+NONE Means nothing is enabled. This disables even
+ protocol versions. It should be followed by the
+ algorithms to be enabled. Note that using this
+ option to build a priority string gives detailed
+ control into the resulting settings, however
+ with new revisions of the TLS protocol new
+ priority items are routinely added, and such
+ strings are not forward compatible with new
+ protocols. As such, we advice against using
+ that option for applications targeting multiple
+ versions of the GnuTLS library, and recommend
+ using the defaults (see above) or adjusting the
+ defaults via
+ *note gnutls_set_default_priority_append::.
+
+
+
+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; for certificate types
+X.509. In key exchange algorithms when in NORMAL or SECURE levels the
+perfect forward secrecy algorithms take precedence of the other
+protocols. In all cases all the supported key exchange algorithms are
+enabled.
+
+Note that the SECURE levels distinguish between overall security level
+and message authenticity security level. That is because the message
+authenticity security level requires the adversary to break the
+algorithms at real-time during the protocol run, whilst the overall
+security level refers to off-line adversaries (e.g. adversaries
+breaking the ciphertext years after it was captured).
+
+The NONE keyword, if used, must followed by keywords specifying the
+algorithms and protocols to be enabled. The other initial keywords do
+not require, but may be followed by such keywords. All level keywords
+can be combined, and for example a level of "SECURE256:+SECURE128" is
+allowed.
+
+The order with which every algorithm or protocol is specified is
+significant. Algorithms specified before others will take precedence.
+The supported in the GnuTLS version corresponding to this document
+algorithms and protocols are shown in *note Table 6.4:
+tab:prio-algorithms.; to list the supported algorithms in your currently
+using version use 'gnutls-cli -l'.
+
+To avoid collisions in order to specify a protocol version with "VERS-",
+signature algorithms with "SIGN-" and certificate types with "CTYPE-".
+All other algorithms don't need a prefix. Each specified keyword
+(except for _special keywords_) can be prefixed with any of the
+following characters.
+
+'!' or '-'
+ appended with an algorithm will remove this algorithm.
+"+"
+ appended with an algorithm will add this algorithm.
+
+Type Keywords
+------------------------------------------------------------------
+Ciphers Examples are AES-128-GCM, AES-256-GCM,
+ AES-256-CBC, GOST28147-TC26Z-CNT; see also
+ *note Table 3.1: tab:ciphers. for more options.
+ Catch all name is CIPHER-ALL which will add all
+ the algorithms from NORMAL priority. The
+ shortcut for secure GOST algorithms is
+ CIPHER-GOST-ALL.
+
+Key exchange RSA, RSA-PSK, RSA-EXPORT, DHE-RSA, DHE-DSS, SRP,
+ SRP-RSA, SRP-DSS, PSK, DHE-PSK, ECDHE-PSK,
+ ECDHE-RSA, ECDHE-ECDSA, VKO-GOST-12, ANON-ECDH,
+ ANON-DH. Catch all name is KX-ALL which will add
+ all the algorithms from NORMAL priority. Under
+ TLS1.3, the DHE-PSK and ECDHE-PSK strings are
+ equivalent and instruct for a Diffie-Hellman key
+ exchange using the enabled groups. The shortcut
+ for secure GOST algorithms is KX-GOST-ALL.
+
+MAC MD5, SHA1, SHA256, SHA384, GOST28147-TC26Z-IMIT,
+ AEAD (used with GCM ciphers only). All
+ algorithms from NORMAL priority can be accessed
+ with MAC-ALL. The shortcut for secure GOST
+ algorithms is MAC-GOST-ALL.
+
+Compression COMP-NULL, COMP-DEFLATE. Catch all is COMP-ALL.
+algorithms
+TLS versions VERS-TLS1.0, VERS-TLS1.1, VERS-TLS1.2,
+ VERS-TLS1.3, VERS-DTLS0.9, VERS-DTLS1.0,
+ VERS-DTLS1.2. Catch all are VERS-ALL, and will
+ enable all protocols from NORMAL priority. To
+ distinguish between TLS and DTLS versions you
+ can use VERS-TLS-ALL and VERS-DTLS-ALL.
+
+Signature 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,
+ SIGN-ECDSA-SHA1, SIGN-ECDSA-SHA224,
+ SIGN-ECDSA-SHA256, SIGN-ECDSA-SHA384,
+ SIGN-ECDSA-SHA512, SIGN-EdDSA-Ed25519,
+ SIGN-EdDSA-Ed448, SIGN-RSA-PSS-SHA256,
+ SIGN-RSA-PSS-SHA384, SIGN-RSA-PSS-SHA512,
+ SIGN-GOSTR341001, SIGN-GOSTR341012-256,
+ SIGN-GOSTR341012-512. Catch all which enables
+ all algorithms from NORMAL priority is SIGN-ALL.
+ Shortcut which enables secure GOST algorithms is
+ SIGN-GOST-ALL. This option is only considered
+ for TLS 1.2 and later.
+
+Groups GROUP-SECP192R1, GROUP-SECP224R1,
+ GROUP-SECP256R1, GROUP-SECP384R1,
+ GROUP-SECP521R1, GROUP-X25519, GROUP-X448,
+ GROUP-GC256B, GROUP-GC512A, GROUP-FFDHE2048,
+ GROUP-FFDHE3072, GROUP-FFDHE4096,
+ GROUP-FFDHE6144, and GROUP-FFDHE8192. Groups
+ include both elliptic curve groups, e.g.,
+ SECP256R1, as well as finite field groups such
+ as FFDHE2048. Catch all which enables all
+ groups from NORMAL priority is GROUP-ALL. The
+ helper keywords GROUP-DH-ALL, GROUP-GOST-ALL and
+ GROUP-EC-ALL are also available, restricting the
+ groups to finite fields (DH), GOST curves and
+ generic elliptic curves.
+
+Elliptic CURVE-SECP192R1, CURVE-SECP224R1,
+curves CURVE-SECP256R1, CURVE-SECP384R1,
+(legacy) CURVE-SECP521R1, CURVE-X25519, and CURVE-X448.
+ Catch all which enables all curves from NORMAL
+ priority is CURVE-ALL. Note that the CURVE
+ keyword is kept for backwards compatibility
+ only, for new applications see the GROUP keyword
+ above.
+
+Certificate Certificate types can be given in a symmetric
+types fashion (i.e. the same for both client and
+ server) or, as of GnuTLS 3.6.4, in an asymmetric
+ fashion (i.e. different for the client than for
+ the server). Alternative certificate types must
+ be explicitly enabled via flags in
+ *note gnutls_init::.
+
+ The currently supported types are CTYPE-X509,
+ CTYPE-RAWPK which apply both to client and
+ server; catch all is CTYPE-ALL. The types
+ CTYPE-CLI-X509, CTYPE-SRV-X509, CTYPE-CLI-RAWPK,
+ CTYPE-SRV-RAWPK can be used to specialize on
+ client or server; catch all is CTYPE-CLI-ALL and
+ CTYPE-SRV-ALL. The type 'X509' is aliased to
+ 'X.509' for legacy reasons.
+
+Generic The keyword GOST is a shortcut for secure GOST
+ algorithms (MACs, ciphers, KXes, groups and
+ signatures). For example the following string
+ will enable all TLS 1.2 GOST ciphersuites:
+ 'NONE:+VERS-TLS1.2:+GOST'.
+
+
+
+Table 6.4: The supported algorithm keywords in priority strings.
+
+Note that the finite field groups (indicated by the FFDHE prefix) and
+DHE key exchange methods are generally slower(1) than their elliptic
+curves counterpart (ECDHE).
+
+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 will tolerate
+ packets over the maximum
+ allowed TLS record, and add a
+ padding to TLS Client Hello
+ packet to prevent it being in
+ the 256-512 range which is
+ known to be causing issues
+ with a commonly used firewall
+ (see the %DUMBFW option).
+
+%DUMBFW will add a private extension
+ with bogus data that make the
+ client hello exceed 512 bytes.
+ This avoids a black hole
+ behavior in some firewalls.
+ This is the [*note RFC7685::]
+ client hello padding
+ extension, also enabled with
+ %COMPAT.
+
+%NO_EXTENSIONS will prevent the sending of
+ any TLS extensions in client
+ side. Note that TLS 1.2
+ requires extensions to be
+ used, as well as safe
+ renegotiation thus this option
+ must be used with care. When
+ this option is set no versions
+ later than TLS1.2 can be
+ negotiated.
+
+%NO_TICKETS will prevent the advertizing
+ of the TLS session ticket
+ extension.
+
+%NO_TICKETS_TLS12 will prevent the advertizing
+ of the TLS session ticket
+ extension in TLS 1.2. This is
+ implied by the PFS keyword.
+
+%NO_SESSION_HASH will prevent the advertizing
+ the TLS extended master secret
+ (session hash) extension.
+
+%SERVER_PRECEDENCE The ciphersuite will be
+ selected according to server
+ priorities and not the
+ client's.
+
+%SSL3_RECORD_VERSION will use SSL3.0 record version
+ in client hello. By default
+ GnuTLS will set the minimum
+ supported version as the
+ client hello record version
+ (do not confuse that version
+ with the proposed handshake
+ version at the client hello).
+
+%LATEST_RECORD_VERSION will use the latest TLS
+ version record version in
+ client hello.
+
+
+
+Table 6.5: Special priority string keywords.
+
+Keyword Description
+
+------------------------------------------------------------------
+%STATELESS_COMPRESSION ignored; no longer used.
+
+%DISABLE_WILDCARDS will disable matching
+ wildcards when comparing
+ hostnames in certificates.
+
+%NO_ETM will disable the
+ encrypt-then-mac TLS extension
+ (RFC7366). This is implied by
+ the %COMPAT keyword.
+
+%FORCE_ETM negotiate CBC ciphersuites
+ only when both sides of the
+ connection support
+ encrypt-then-mac TLS extension
+ (RFC7366).
+
+%DISABLE_SAFE_RENEGOTIATION will completely disable safe
+ renegotiation 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.
+
+%FALLBACK_SCSV will enable the use of the
+ fallback signaling cipher
+ suite value in the client
+ hello. Note that this should
+ be set only by applications
+ that try to reconnect with a
+ downgraded protocol version.
+ See RFC7507 for details.
+
+%DISABLE_TLS13_COMPAT_MODE will disable TLS 1.3 middlebox
+ compatibility mode (RFC8446,
+ Appendix D.4) for
+ non-compliant middleboxes.
+
+%VERIFY_ALLOW_BROKEN will allow signatures with
+ known to be broken algorithms
+ (such as MD5 or SHA1) in
+ certificate chains.
+
+%VERIFY_ALLOW_SIGN_RSA_MD5 will allow RSA-MD5 signatures
+ in certificate chains.
+
+%VERIFY_ALLOW_SIGN_WITH_SHA1 will allow signatures with
+ SHA1 hash algorithm in
+ certificate chains.
+
+%VERIFY_DISABLE_CRL_CHECKS will disable CRL or OCSP
+ checks in the verification of
+ the certificate chain.
+
+%VERIFY_ALLOW_X509_V1_CA_CRT will allow V1 CAs in chains.
+
+%PROFILE_(LOW|LEGACY|MEDIUM|HIGH|ULTRA|FUTURE)require a certificate
+ verification profile the
+ corresponds to the specified
+ security level, see
+ *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 plus ARCFOUR-128:
+ "NORMAL:+ARCFOUR-128"
+
+ Enabling the 128-bit secure ciphers, while disabling TLS 1.0:
+ "SECURE128:-VERS-TLS1.0"
+
+ Enabling the 128-bit and 192-bit secure ciphers, while disabling all TLS versions
+ except TLS 1.2:
+ "SECURE128:+SECURE192:-VERS-ALL:+VERS-TLS1.2"
+
+ ---------- Footnotes ----------
+
+ (1) It depends on the group in use. Groups with less bits are always
+faster, but the number of bits ties with the security parameter. See
+*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 [*note
+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 (profile)
+ 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
+ (corresponds to ENISA
+ future level)
+
+192 8192 384 'ULTRA' Even longer term
+ protection
+
+256 15424 512 'FUTURE' 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 [*note 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:
+
+* Virtual hosts and credentials::
+* Session resumption::
+* Certificate verification::
+* TLS 1.2 re-authentication::
+* TLS 1.3 re-authentication and re-key::
+* Parameter generation::
+* Deriving keys for other applications/protocols::
+* Channel Bindings::
+* Interoperability::
+* Compatibility with the OpenSSL library::
+
+
+File: gnutls.info, Node: Virtual hosts and credentials, Next: Session resumption, Up: Advanced topics
+
+6.12.1 Virtual hosts and credentials
+------------------------------------
+
+Often when operating with virtual hosts, one may not want to associate a
+particular certificate set to the credentials function early, before the
+virtual host is known. That can be achieved by calling *note
+gnutls_credentials_set:: within a handshake pre-hook for client hello.
+That message contains the peer's intended hostname, and if read, and the
+appropriate credentials are set, gnutls will be able to continue in the
+handshake process. A brief usage example is shown below.
+
+ static int ext_hook_func(void *ctx, unsigned tls_id,
+ const unsigned char *data, unsigned size)
+ {
+ if (tls_id == 0) { /* server name */
+ /* figure the advertized name - the following hack
+ * relies on the fact that this extension only supports
+ * DNS names, and due to a protocol bug cannot be extended
+ * to support anything else. */
+ if (name < 5) return 0;
+ name = data+5;
+ name_size = size-5;
+ }
+ return 0;
+ }
+
+ static int
+ handshake_hook_func(gnutls_session_t session, unsigned int htype,
+ unsigned when, unsigned int incoming, const gnutls_datum_t *msg)
+ {
+ int ret;
+
+ assert(htype == GNUTLS_HANDSHAKE_CLIENT_HELLO);
+ assert(when == GNUTLS_HOOK_PRE);
+
+ ret = gnutls_ext_raw_parse(NULL, ext_hook_func, msg,
+ GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
+ assert(ret >= 0);
+
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
+
+ return ret;
+ }
+
+ int main()
+ {
+ ...
+
+ gnutls_handshake_set_hook_function(server, GNUTLS_HANDSHAKE_CLIENT_HELLO,
+ GNUTLS_HOOK_PRE, handshake_hook_func);
+ ...
+ }
+
+ -- Function: void gnutls_handshake_set_hook_function (gnutls_session_t
+ SESSION, unsigned int HTYPE, int WHEN,
+ gnutls_handshake_hook_func FUNC)
+ SESSION: is a 'gnutls_session_t' type
+
+ HTYPE: the 'gnutls_handshake_description_t' of the message to hook
+ at
+
+ WHEN: 'GNUTLS_HOOK_' * depending on when the hook function should
+ be called
+
+ FUNC: is the function to be called
+
+ This function will set a callback to be called after or before the
+ specified handshake message has been received or generated. This
+ is a generalization of
+ 'gnutls_handshake_set_post_client_hello_function()' .
+
+ To call the hook function prior to the message being generated or
+ processed use 'GNUTLS_HOOK_PRE' as 'when' parameter,
+ 'GNUTLS_HOOK_POST' to call after, and 'GNUTLS_HOOK_BOTH' for both
+ cases.
+
+ This callback must return 0 on success or a gnutls error code to
+ terminate the handshake.
+
+ To hook at all handshake messages use an 'htype' of
+ 'GNUTLS_HANDSHAKE_ANY' .
+
+ *Warning:* You should not use this function to terminate the
+ handshake based on client input unless you know what you are doing.
+ Before the handshake is finished there is no way to know if there
+ is a man-in-the-middle attack being performed.
+
+
+File: gnutls.info, Node: Session resumption, Next: Certificate verification, Prev: Virtual hosts and credentials, Up: Advanced topics
+
+6.12.2 Session resumption
+-------------------------
+
+To reduce time and network traffic spent in a handshake the client can
+request session resumption from a server that previously shared a
+session with the client.
+
+Under TLS 1.2, in order to support resumption a server can either store
+the session security parameters in a local database or use session
+tickets (see *note Session tickets::) to delegate storage to the client.
+
+Under TLS 1.3, session resumption is only available through session
+tickets, and multiple tickets could be sent from server to client. That
+provides the following advantages:
+ * When tickets are not re-used the subsequent client sessions cannot
+ be associated with each other by an eavesdropper
+ * On post-handshake authentication the server may send different
+ tickets asynchronously for each identity used by client.
+
+Client side
+...........
+
+The client has to retrieve and store the session parameters. Before
+establishing a new session to the same server the parameters must be
+re-associated with the GnuTLS session using *note
+gnutls_session_set_data::.
+
+'INT *note gnutls_session_get_data2:: (gnutls_session_t SESSION, gnutls_datum_t * DATA)'
+'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' type.
+
+ Checks whether session is resumed or not. This is functional for
+ both server and client side.
+
+ *Returns:* non zero if this session is resumed, or a zero if this
+ is a new session.
+
+ -- Function: int gnutls_session_get_id2 (gnutls_session_t SESSION,
+ gnutls_datum_t * SESSION_ID)
+ SESSION: is a 'gnutls_session_t' type.
+
+ SESSION_ID: will point to the session ID.
+
+ Returns the TLS session identifier. The session ID is selected by
+ the server, and in older versions of TLS was a unique identifier
+ shared between client and server which was persistent across
+ resumption. In the latest version of TLS (1.3) or TLS 1.2 with
+ session tickets, the notion of session identifiers is undefined and
+ cannot be relied for uniquely identifying sessions across client
+ and server.
+
+ In client side this function returns the identifier returned by the
+ server, and cannot be assumed to have any relation to session
+ resumption. In server side this function is guaranteed to return a
+ persistent identifier of the session since GnuTLS 3.6.4, which may
+ not necessarily map into the TLS session ID value. Prior to that
+ version the value could only be considered a persistent identifier,
+ under TLS1.2 or earlier and when no session tickets were in use.
+
+ The session identifier value returned is always less than
+ 'GNUTLS_MAX_SESSION_ID_SIZE' and should be treated as constant.
+
+ *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned,
+ otherwise an error code is returned.
+
+ *Since:* 3.1.4
+
+Server side
+...........
+
+A server enabling both session tickets and a storage for session data
+would use session tickets when clients support it and the storage
+otherwise.
+
+A storing server needs to specify callback functions to store, retrieve
+and delete session data. These can be registered with the functions
+below. The stored sessions in the database can be checked using *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 supporting session tickets must 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::.
+
+Those will be the initial keys, but GnuTLS will rotate them regularly.
+The key rotation interval can be changed with *note
+gnutls_db_set_cache_expiration:: and will be set to three times the
+ticket expiration time (ie. three times the value given in that
+function). Every such interval, new keys will be generated from those
+initial keys. This is a necessary mechanism to prevent the keys from
+becoming long-term keys and as such preserve forward-secrecy in the
+issued session tickets. If no explicit key rotation interval is
+provided, GnuTLS will rotate them every 18 hours by default.
+
+The master key can be shared between processes or between systems.
+Processes which share the same master key will generate the same rotated
+subkeys, assuming they share the same time (irrespective of timezone
+differences).
+
+ -- Function: int gnutls_session_ticket_enable_server (gnutls_session_t
+ SESSION, const gnutls_datum_t * KEY)
+ SESSION: is a 'gnutls_session_t' type.
+
+ KEY: key to encrypt session parameters.
+
+ Request that the server should attempt session resumption using
+ session tickets, i.e., by delegating storage to the client. 'key'
+ must be initialized using 'gnutls_session_ticket_key_generate()' .
+ To avoid leaking that key, use 'gnutls_memset()' prior to releasing
+ it.
+
+ The default ticket expiration time can be overridden using
+ 'gnutls_db_set_cache_expiration()' .
+
+ *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' type.
+
+ 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.
+
+The expiration time for session resumption, either in tickets or stored
+data is set using *note gnutls_db_set_cache_expiration::. This function
+also controls the ticket key rotation period. Currently, the session
+key rotation interval is set to 3 times the expiration time set by this
+function.
+
+Under TLS 1.3, the server sends by default 2 tickets, and can send
+additional session tickets at any time using *note
+gnutls_session_ticket_send::.
+
+ -- Function: int gnutls_session_ticket_send (gnutls_session_t SESSION,
+ unsigned NR, unsigned FLAGS)
+ SESSION: is a 'gnutls_session_t' type.
+
+ NR: the number of tickets to send
+
+ FLAGS: must be zero
+
+ Sends a fresh session ticket to the peer. This is relevant only in
+ server side under TLS1.3. This function may also return
+ 'GNUTLS_E_AGAIN' or 'GNUTLS_E_INTERRUPTED' and in that case it must
+ be called again.
+
+ *Returns:* 'GNUTLS_E_SUCCESS' on success, or a negative error code.
+
+
+File: gnutls.info, Node: Certificate verification, Next: TLS 1.2 re-authentication, Prev: Session resumption, Up: Advanced topics
+
+6.12.3 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.3.1 Trust on first use
+...........................
+
+The GnuTLS library includes functionality to use an SSH-like trust on
+first use authentication. The available functions to store and verify
+public keys are listed below.
+
+ -- 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 a raw public-key or a public-key
+ provided via a raw (DER-encoded) certificate using a list of stored
+ public keys. The 'service' field if non-NULL should be a port
+ number.
+
+ The 'db_name' 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.
+
+ As of GnuTLS 3.6.6 this function also verifies raw public keys.
+
+ *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 a raw public-key or a public-key provided
+ via a raw (DER-encoded) certificate to the list of stored public
+ keys. The key will be considered valid until the provided
+ expiration time.
+
+ The 'tdb' 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.
+
+ Unless an alternative 'tdb' is provided, the storage format is a
+ textual format consisting of a line for each host with fields
+ separated by '|'. The contents of the fields are a
+ format-identifier which is set to 'g0', the hostname that the rest
+ of the data applies to, the numeric port or host name, the
+ expiration time in seconds since the epoch (0 for no expiration),
+ and a base64 encoding of the raw (DER) public key information
+ (SPKI) of the peer.
+
+ As of GnuTLS 3.6.6 this function also accepts raw public keys.
+
+ *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 [*note 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 or 'GNUTLS_SCOMMIT_FLAG_ALLOW_BROKEN' .
+
+ 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 'tdb' 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.3.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 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 optimize against multiple re-initializations of the
+resolving back-end and loading of DNSSEC keys.
+
+The following flags are returned by the verify functions to indicate the
+status of the verification.
+
+'DANE_VERIFY_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.3: 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: TLS 1.2 re-authentication, Next: TLS 1.3 re-authentication and re-key, Prev: Certificate verification, Up: Advanced topics
+
+6.12.4 TLS 1.2 re-authentication
+--------------------------------
+
+In TLS 1.2 or earlier there is no distinction between re-key,
+re-authentication, and re-negotiation. All of these use cases are
+handled by the TLS' rehandshake process. For that reason in GnuTLS
+rehandshake is not transparent to the application, and the application
+must explicitly take control of that process. In addition GnuTLS since
+version 3.5.0 will not allow the peer to switch identities during a
+rehandshake. The threat addressed by that behavior depends on the
+application protocol, but primarily it protects applications from being
+misled by a rehandshake which switches the peer's identity.
+Applications can disable this protection by using the
+'GNUTLS_ALLOW_ID_CHANGE' flag in *note gnutls_init::.
+
+The following paragraphs explain how to safely use the rehandshake
+process.
+
+6.12.4.1 Client side
+....................
+
+According to the TLS specification a client may initiate a rehandshake
+at any time. That can be achieved by calling *note gnutls_handshake::
+and rely on its return value for the outcome of the handshake (the
+server may deny a rehandshake). If a server requests a re-handshake,
+then a call to *note gnutls_record_recv:: will return
+GNUTLS_E_REHANDSHAKE in the client, instructing it to call *note
+gnutls_handshake::. To deny a rehandshake request by the server it is
+recommended to send a warning alert of type GNUTLS_A_NO_RENEGOTIATION.
+
+Due to limitations of early protocol versions, it is required to check
+whether safe renegotiation is in place, i.e., using *note
+gnutls_safe_renegotiation_status::, which ensures that the server
+remains the same as the initial.
+
+To make re-authentication transparent to the application when requested
+by the server, use the 'GNUTLS_AUTO_REAUTH' flag on the *note
+gnutls_init:: call. In that case the re-authentication will happen in
+the call of *note gnutls_record_recv:: that received the
+reauthentication request.
+
+ -- Function: unsigned gnutls_safe_renegotiation_status
+ (gnutls_session_t SESSION)
+ SESSION: is a 'gnutls_session_t' type.
+
+ Can be used to check whether safe renegotiation is being used in
+ the current session.
+
+ *Returns:* 0 when safe renegotiation is not used and non (0) when
+ safe renegotiation is used.
+
+ *Since:* 2.10.0
+
+6.12.4.2 Server side
+....................
+
+A server which wants to instruct the client to re-authenticate, should
+call *note gnutls_rehandshake:: and wait for the client to
+re-authenticate. It is recommended to only request re-handshake when
+safe renegotiation is enabled for that session (see *note
+gnutls_safe_renegotiation_status:: and the discussion in *note Safe
+renegotiation::). A server could also encounter the
+GNUTLS_E_REHANDSHAKE error code while receiving data. That indicates a
+client-initiated re-handshake request. In that case the server could
+ignore that request, perform handshake (unsafe when done generally), or
+even drop the connection.
+
+ -- Function: int gnutls_rehandshake (gnutls_session_t SESSION)
+ SESSION: is a 'gnutls_session_t' type.
+
+ This function can only be called in server side, and instructs a
+ TLS 1.2 or earlier client to renegotiate parameters (perform a
+ handshake), by sending a hello request message.
+
+ If this function succeeds, the calling application should call
+ 'gnutls_record_recv()' until 'GNUTLS_E_REHANDSHAKE' is returned to
+ clear any pending data. If the 'GNUTLS_E_REHANDSHAKE' error code
+ is not seen, then the handshake request was not followed by the
+ peer (the TLS protocol does not require the client to do, and such
+ compliance should be handled by the application protocol).
+
+ Once the 'GNUTLS_E_REHANDSHAKE' error code is seen, the calling
+ application should proceed to calling 'gnutls_handshake()' to
+ negotiate the new parameters.
+
+ If the client does not wish to renegotiate parameters he may reply
+ with an alert message, and in that case the return code seen by
+ subsequent 'gnutls_record_recv()' will be
+ 'GNUTLS_E_WARNING_ALERT_RECEIVED' with the specific alert being
+ 'GNUTLS_A_NO_RENEGOTIATION' . A client may also choose to ignore
+ this request.
+
+ Under TLS 1.3 this function is equivalent to
+ 'gnutls_session_key_update()' with the 'GNUTLS_KU_PEER' flag. In
+ that case subsequent calls to 'gnutls_record_recv()' will not
+ return 'GNUTLS_E_REHANDSHAKE' , and calls to 'gnutls_handshake()'
+ in server side are a no-op.
+
+ This function always fails with 'GNUTLS_E_INVALID_REQUEST' when
+ called in client side.
+
+ *Returns:* 'GNUTLS_E_SUCCESS' on success, otherwise a negative
+ error code.
+
+
+File: gnutls.info, Node: TLS 1.3 re-authentication and re-key, Next: Parameter generation, Prev: TLS 1.2 re-authentication, Up: Advanced topics
+
+6.12.5 TLS 1.3 re-authentication and re-key
+-------------------------------------------
+
+The TLS 1.3 protocol distinguishes between re-key and re-authentication.
+The re-key process ensures that fresh keys are supplied to the already
+negotiated parameters, and on GnuTLS can be initiated using *note
+gnutls_session_key_update::. The re-key process can be one-way (i.e.,
+the calling party only changes its keys), or two-way where the peer is
+requested to change keys as well.
+
+The re-authentication process, allows the connected client to switch
+identity by presenting a new certificate. Unlike TLS 1.2, the server is
+not allowed to change identities. That client re-authentication, or
+post-handshake authentication can be initiated only by the server using
+*note gnutls_reauth::, and only if a client has advertized support for
+it. Both server and client have to explicitly enable support for post
+handshake authentication using the 'GNUTLS_POST_HANDSHAKE_AUTH' flag at
+*note gnutls_init::.
+
+A client receiving a re-authentication request will "see" the error code
+'GNUTLS_E_REAUTH_REQUEST' at *note gnutls_record_recv::. At this point,
+it should also call *note gnutls_reauth::.
+
+To make re-authentication transparent to the application when requested
+by the server, use the 'GNUTLS_AUTO_REAUTH' and
+'GNUTLS_POST_HANDSHAKE_AUTH' flags on the *note gnutls_init:: call. In
+that case the re-authentication will happen in the call of *note
+gnutls_record_recv:: that received the reauthentication request.
+
+
+File: gnutls.info, Node: Parameter generation, Next: Deriving keys for other applications/protocols, Prev: TLS 1.3 re-authentication and re-key, Up: Advanced topics
+
+6.12.6 Parameter generation
+---------------------------
+
+Prior to GnuTLS 3.6.0 for the ephemeral or anonymous Diffie-Hellman (DH)
+TLS ciphersuites the application was required to generate or provide DH
+parameters. That is no longer necessary as GnuTLS utilizes DH
+parameters and negotiation from [*note RFC7919::].
+
+Applications can tune the used parameters by explicitly specifying them
+in the priority string. In server side applications can set the minimum
+acceptable level of DH parameters by calling *note
+gnutls_certificate_set_known_dh_params::, *note
+gnutls_anon_set_server_known_dh_params::, or *note
+gnutls_psk_set_server_known_dh_params::, depending on the type of the
+credentials, to set the lower acceptable parameter limits. Typical
+applications should rely on the default settings.
+
+'INT *note gnutls_certificate_set_known_dh_params:: (gnutls_certificate_credentials_t RES, gnutls_sec_param_t SEC_PARAM)'
+'INT *note gnutls_anon_set_server_known_dh_params:: (gnutls_anon_server_credentials_t RES, gnutls_sec_param_t SEC_PARAM)'
+'INT *note gnutls_psk_set_server_known_dh_params:: (gnutls_psk_server_credentials_t RES, gnutls_sec_param_t SEC_PARAM)'
+
+6.12.6.1 Legacy parameter generation
+....................................
+
+Note that older than 3.5.6 versions of GnuTLS provided functions to
+generate or import arbitrary DH parameters from a file. This practice
+is still supported but discouraged in current versions. There is no
+known advantage from using random parameters, while there have been
+several occasions where applications were utilizing incorrect, weak or
+insecure parameters. This is the main reason GnuTLS includes the
+well-known parameters of [*note RFC7919::] and recommends applications
+utilizing them.
+
+In older applications which require to specify explicit DH parameters,
+we recommend using 'certtool' (of GnuTLS 3.5.6 or later) with the
+'--get-dh-params' option to obtain the FFDHE parameters discussed above.
+The output parameters of the tool are in PKCS#3 format and can be
+imported by most existing applications.
+
+The following functions are still supported but considered obsolete.
+
+'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)'
+
+
+File: gnutls.info, Node: Deriving keys for other applications/protocols, Next: Channel Bindings, Prev: Parameter generation, Up: Advanced topics
+
+6.12.7 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_rfc5705::. The function needs to be
+provided with a label, and additional context data to mix in the
+'context' parameter.
+
+ -- Function: int gnutls_prf_rfc5705 (gnutls_session_t SESSION, size_t
+ LABEL_SIZE, const char * LABEL, size_t CONTEXT_SIZE, const
+ char * CONTEXT, size_t OUTSIZE, char * OUT)
+ SESSION: is a 'gnutls_session_t' type.
+
+ LABEL_SIZE: length of the 'label' variable.
+
+ LABEL: label used in PRF computation, typically a short string.
+
+ CONTEXT_SIZE: length of the 'extra' variable.
+
+ CONTEXT: optional extra data to seed the PRF with.
+
+ OUTSIZE: size of pre-allocated output buffer to hold the output.
+
+ OUT: pre-allocated buffer to hold the generated data.
+
+ Exports keying material from TLS/DTLS session to an application, as
+ specified in RFC5705.
+
+ In the TLS versions prior to 1.3, it applies the TLS
+ Pseudo-Random-Function (PRF) on the master secret and the provided
+ data, seeded with the client and server random fields.
+
+ In TLS 1.3, it applies HKDF on the exporter master secret derived
+ from the master secret.
+
+ The 'label' variable usually contains a string denoting the purpose
+ for the generated data.
+
+ The 'context' variable can be used to add more data to the seed,
+ after the random variables. It can be used to make sure the
+ generated output is strongly connected to some additional data
+ (e.g., a string used in user authentication).
+
+ The output is placed in 'out' , which must be pre-allocated.
+
+ Note that, to provide the RFC5705 context, the 'context' variable
+ must be non-null.
+
+ *Returns:* 'GNUTLS_E_SUCCESS' on success, or an error code.
+
+ *Since:* 3.4.4
+
+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_rfc5705 (session, sizeof(MYLABEL)-1, MYLABEL,
+ sizeof(MYCONTEXT)-1, MYCONTEXT, 32, out);
+
+The output key depends on TLS' master secret, and is the same on both
+client and server.
+
+For legacy applications which need to use a more flexible API, there is
+*note gnutls_prf::, which in addition, allows to switch the mix of the
+client and server random nonces, using the 'server_random_first'
+parameter. For additional flexibility and low-level access to the
+TLS1.2 PRF, there is a low-level TLS PRF interface called *note
+gnutls_prf_raw::. That however is not functional under newer protocol
+versions.
+
+
+File: gnutls.info, Node: Channel Bindings, Next: Interoperability, Prev: Deriving keys for other applications/protocols, Up: Advanced topics
+
+6.12.8 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 [*note RFC5056::].
+
+In GnuTLS you can extract a channel binding using the *note
+gnutls_session_channel_binding:: function. Currently only the following
+types are supported:
+
+ * 'GNUTLS_CB_TLS_UNIQUE': corresponds to the 'tls-unique' channel
+ binding for TLS defined in [*note RFC5929::]
+ * 'GNUTLS_CB_TLS_EXPORTER': corresponds to the 'tls-exporter' channel
+ binding for TLS defined in [*note RFC9266::]
+
+The following example describes how to print the channel binding data.
+Note that it must be run after a successful TLS handshake.
+
+ {
+ gnutls_datum_t cb;
+ int rc;
+
+ rc = gnutls_session_channel_binding (session,
+ GNUTLS_CB_TLS_UNIQUE,
+ &cb);
+ if (rc)
+ fprintf (stderr, "Channel binding error: %s\n",
+ gnutls_strerror (rc));
+ else
+ {
+ size_t i;
+ printf ("- Channel binding 'tls-unique': ");
+ for (i = 0; i < cb.size; i++)
+ printf ("%02x", cb.data[i]);
+ printf ("\n");
+ }
+ }
+
+
+File: gnutls.info, Node: Interoperability, Next: Compatibility with the OpenSSL library, Prev: Channel Bindings, Up: Advanced topics
+
+6.12.9 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 very old broken peers that do not tolerate TLS version numbers over
+TLS 1.0 another priority string is:
+NORMAL:-VERS-ALL:+VERS-TLS1.0:+VERS-SSL3.0:%COMPAT
+This priority string will in addition to above, only enable SSL 3.0 and
+TLS 1.0 as protocols.
+
+
+File: gnutls.info, Node: Compatibility with the OpenSSL library, Prev: Interoperability, Up: Advanced topics
+
+6.12.10 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: System-wide configuration of the 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::
+* More advanced client and servers::
+* 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:
+
+* Client example with X.509 certificate support::
+* Datagram TLS client example::
+* Client using a smart card with TLS::
+* Client with Resume capability example::
+* Client example with SSH-style certificate verification::
+
+
+File: gnutls.info, Node: Client example with X.509 certificate support, Next: Datagram TLS client example, Up: Client examples
+
+7.1.1 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 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.
+
+Note that this client utilizes functionality present in the latest
+GnuTLS version. For a reasonably portable version see *note Legacy
+client example with X.509 certificate support::.
+
+/* 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 <assert.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 recovery is minimal for simplicity.
+ */
+
+#define CHECK(x) assert((x)>=0)
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
+ assert(rval >= 0)
+
+#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], *desc;
+ gnutls_datum_t out;
+ int type;
+ unsigned status;
+ gnutls_certificate_credentials_t xcred;
+
+ if (gnutls_check_version("3.4.6") == NULL) {
+ fprintf(stderr, "GnuTLS 3.4.6 or later is required for this example\n");
+ exit(1);
+ }
+
+ /* for backwards compatibility with gnutls < 3.3.0 */
+ CHECK(gnutls_global_init());
+
+ /* X509 stuff */
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+
+ /* sets the system trusted CAs for Internet PKI */
+ CHECK(gnutls_certificate_set_x509_system_trust(xcred));
+
+ /* 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 */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ CHECK(gnutls_server_name_set(session, GNUTLS_NAME_DNS, "www.example.com",
+ strlen("www.example.com")));
+
+ /* It is recommended to use the default priorities */
+ CHECK(gnutls_set_default_priority(session));
+
+ /* put the x509 credentials to the current session
+ */
+ CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred));
+ gnutls_session_set_verify_cert(session, "www.example.com", 0);
+
+ /* 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) {
+ if (ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR) {
+ /* check certificate verification status */
+ type = gnutls_certificate_type_get(session);
+ status = gnutls_session_get_verify_cert_status(session);
+ CHECK(gnutls_certificate_verification_status_print(status,
+ type, &out, 0));
+ printf("cert verify output: %s\n", out.data);
+ gnutls_free(out.data);
+ }
+ fprintf(stderr, "*** Handshake failed: %s\n", gnutls_strerror(ret));
+ goto end;
+ } else {
+ desc = gnutls_session_get_desc(session);
+ printf("- Session info: %s\n", desc);
+ gnutls_free(desc);
+ }
+
+ /* send data */
+ LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
+
+ LOOP_CHECK(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);
+ }
+
+ CHECK(gnutls_bye(session, GNUTLS_SHUT_RDWR));
+
+ end:
+
+ tcp_close(sd);
+
+ gnutls_deinit(session);
+
+ gnutls_certificate_free_credentials(xcred);
+
+ gnutls_global_deinit();
+
+ return 0;
+}
+
+
+File: gnutls.info, Node: Datagram TLS client example, Next: Client using a smart card with TLS, Prev: Client example with X.509 certificate support, Up: Client examples
+
+7.1.2 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 <assert.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 CHECK(x) assert((x)>=0)
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
+ assert(rval >= 0)
+
+#define MAX_BUF 1024
+#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];
+ 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 */
+ CHECK(gnutls_global_init());
+
+ /* X509 stuff */
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+
+ /* sets the system trusted CAs for Internet PKI */
+ CHECK(gnutls_certificate_set_x509_system_trust(xcred));
+
+ /* Initialize TLS session */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM));
+
+ /* Use default priorities */
+ CHECK(gnutls_set_default_priority(session));
+
+ /* put the x509 credentials to the current session */
+ CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred));
+ CHECK(gnutls_server_name_set(session, GNUTLS_NAME_DNS, "www.example.com",
+ strlen("www.example.com")));
+
+ gnutls_session_set_verify_cert(session, "www.example.com", 0);
+
+ /* 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);
+ }
+
+ LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
+
+ LOOP_CHECK(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 */
+ CHECK(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: Client using a smart card with TLS, Next: Client with Resume capability example, Prev: Datagram TLS client example, Up: Client examples
+
+7.1.3 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.
+The difference between this and the *note Client example with X.509
+certificate support:: is that the client keys are provided as PKCS #11
+URIs instead of files.
+
+/* 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 <assert.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 CHECK(x) assert((x)>=0)
+
+#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: ");
+ /* FIXME: ensure that we are in UTF-8 locale */
+ 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;
+ 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 */
+ CHECK(gnutls_global_init());
+
+ /* The PKCS11 private key operations may require PIN.
+ * Register a callback. */
+ gnutls_pkcs11_set_pin_function(pin_callback, NULL);
+
+ /* X509 stuff */
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+
+ /* sets the trusted cas file
+ */
+ CHECK(gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
+ GNUTLS_X509_FMT_PEM));
+
+ CHECK(gnutls_certificate_set_x509_key_file(xcred, CERT_URL, KEY_URL,
+ GNUTLS_X509_FMT_DER));
+
+ /* Note that there is no server certificate verification in this example
+ */
+
+
+ /* Initialize TLS session
+ */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ /* Use default priorities */
+ CHECK(gnutls_set_default_priority(session));
+
+ /* put the x509 credentials to the current session
+ */
+ CHECK(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);
+ }
+
+ CHECK(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);
+
+ CHECK(gnutls_bye(session, GNUTLS_SHUT_RDWR));
+
+ end:
+
+ tcp_close(sd);
+
+ gnutls_deinit(session);
+
+ gnutls_certificate_free_credentials(xcred);
+
+ gnutls_global_deinit();
+
+ return 0;
+}
+
+
+File: gnutls.info, Node: Client with Resume capability example, Next: Client example with SSH-style certificate verification, Prev: Client using a smart card with TLS, Up: Client examples
+
+7.1.4 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 <assert.h>
+#include <gnutls/gnutls.h>
+
+extern void check_alert(gnutls_session_t session, int ret);
+extern int tcp_connect(void);
+extern void tcp_close(int sd);
+
+/* A very basic TLS client, with X.509 authentication and server certificate
+ * verification as well as session resumption.
+ *
+ * Note that error recovery is minimal for simplicity.
+ */
+
+#define CHECK(x) assert((x)>=0)
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
+ assert(rval >= 0)
+
+#define MAX_BUF 1024
+#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;
+ gnutls_datum_t sdata;
+
+ /* for backwards compatibility with gnutls < 3.3.0 */
+ CHECK(gnutls_global_init());
+
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+ CHECK(gnutls_certificate_set_x509_system_trust(xcred));
+
+ for (t = 0; t < 2; t++) { /* connect 2 times to the server */
+
+ sd = tcp_connect();
+
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ CHECK(gnutls_server_name_set(session, GNUTLS_NAME_DNS,
+ "www.example.com",
+ strlen("www.example.com")));
+ gnutls_session_set_verify_cert(session, "www.example.com", 0);
+
+ CHECK(gnutls_set_default_priority(session));
+
+ gnutls_transport_set_int(session, sd);
+ gnutls_handshake_set_timeout(session,
+ GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+ xcred);
+
+ if (t > 0) {
+ /* if this is not the first time we connect */
+ CHECK(gnutls_session_set_data(session, sdata.data,
+ sdata.size));
+ gnutls_free(sdata.data);
+ }
+
+ /* 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 */
+ CHECK(gnutls_session_get_data2(session, &sdata));
+ } 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");
+ }
+ }
+
+ LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
+
+ LOOP_CHECK(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: Client example with SSH-style certificate verification, Prev: Client with Resume capability example, Up: Client examples
+
+7.1.5 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 <assert.h>
+#include "examples.h"
+
+#define CHECK(x) assert((x)>=0)
+
+/* 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.
+ */
+ CHECK(gnutls_certificate_verify_peers3(session, hostname, &status));
+
+ type = gnutls_certificate_type_get(session);
+
+ CHECK(gnutls_certificate_verification_status_print(status,
+ type, &out, 0));
+ 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) {
+ CHECK(gnutls_store_pubkey(NULL, NULL, hostname, "https",
+ type, &cert_list[0], 0, 0));
+ }
+
+ /* notify gnutls to continue handshake normally */
+ return 0;
+}
+
+
+File: gnutls.info, Node: Server examples, Next: More advanced client and servers, 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::
+* DTLS echo server with X.509 authentication::
+
+
+File: gnutls.info, Node: Echo server with X.509 authentication, Next: DTLS echo server with X.509 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>
+#include <assert.h>
+
+#define KEYFILE "key.pem"
+#define CERTFILE "cert.pem"
+#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
+#define CRLFILE "crl.pem"
+
+#define CHECK(x) assert((x)>=0)
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
+
+/* 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 */
+
+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 */
+ CHECK(gnutls_global_init());
+
+ CHECK(gnutls_certificate_allocate_credentials(&x509_cred));
+
+ CHECK(gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE,
+ GNUTLS_X509_FMT_PEM));
+
+ CHECK(gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE,
+ GNUTLS_X509_FMT_PEM));
+
+ /* The following code sets the certificate key pair as well as,
+ * an OCSP response which corresponds to it. It is possible
+ * to set multiple key-pairs and multiple OCSP status responses
+ * (the latter since 3.5.6). See the manual pages of the individual
+ * functions for more information.
+ */
+ CHECK(gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE,
+ KEYFILE,
+ GNUTLS_X509_FMT_PEM));
+
+ CHECK(gnutls_certificate_set_ocsp_status_request_file(x509_cred,
+ OCSP_STATUS_FILE,
+ 0));
+
+ CHECK(gnutls_priority_init(&priority_cache, NULL, NULL));
+
+ /* Instead of the default options as shown above one could specify
+ * additional options such as server precedence in ciphersuite selection
+ * as follows:
+ * gnutls_priority_init2(&priority_cache,
+ * "%SERVER_PRECEDENCE",
+ * NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+ */
+
+#if GNUTLS_VERSION_NUMBER >= 0x030506
+ /* only available since GnuTLS 3.5.6, on previous versions see
+ * gnutls_certificate_set_dh_params(). */
+ gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM);
+#endif
+
+ /* 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 (;;) {
+ CHECK(gnutls_init(&session, GNUTLS_SERVER));
+ CHECK(gnutls_priority_set(session, priority_cache));
+ CHECK(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);
+ gnutls_handshake_set_timeout(session,
+ GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+
+ 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);
+
+ LOOP_CHECK(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 (;;) {
+ LOOP_CHECK(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
+ */
+ CHECK(gnutls_record_send(session, buffer, ret));
+ }
+ }
+ printf("\n");
+ /* do not wait for the peer to close the connection.
+ */
+ LOOP_CHECK(ret, 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: DTLS echo server with X.509 authentication, Prev: Echo server with X.509 authentication, Up: Server examples
+
+7.2.2 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 LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
+
+#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);
+
+/* Use global credentials and parameters to simplify
+ * the example. */
+static gnutls_certificate_credentials_t x509_cred;
+static gnutls_priority_t priority_cache;
+
+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);
+ }
+
+ gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM);
+
+ /* pre-3.6.3 equivalent:
+ * gnutls_priority_init(&priority_cache,
+ * "NORMAL:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE",
+ * NULL);
+ */
+ gnutls_priority_init2(&priority_cache,
+ "%SERVER_PRECEDENCE",
+ NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+
+ 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);
+
+ LOOP_CHECK(ret, gnutls_handshake(session));
+ /* 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 (;;) {
+ LOOP_CHECK(ret,
+ gnutls_record_recv_seq(session, buffer,
+ MAX_BUFFER,
+ sequence));
+
+ 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 */
+ LOOP_CHECK(ret, gnutls_record_send(session, buffer, ret));
+ if (ret < 0) {
+ fprintf(stderr, "Error in send(): %s\n",
+ gnutls_strerror(ret));
+ break;
+ }
+ }
+
+ LOOP_CHECK(ret, 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 = ms / 1000;
+ tv.tv_usec = (ms % 1000) * 1000;
+
+ 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;
+}
+
+
+
+File: gnutls.info, Node: More advanced client and servers, Next: OCSP example, Prev: Server examples, Up: GnuTLS application examples
+
+7.3 More advanced client and servers
+====================================
+
+This section has various, more advanced topics in client and servers.
+
+* Menu:
+
+* Client example with anonymous authentication::
+* Using a callback to select the certificate to use::
+* Obtaining session information::
+* Advanced certificate verification example::
+* Client example with PSK authentication::
+* Client example with SRP authentication::
+* Legacy client example with X.509 certificate support::
+* Client example in C++::
+* Echo server with PSK authentication::
+* Echo server with SRP authentication::
+* Echo server with anonymous authentication::
+* Helper functions for TCP connections::
+* Helper functions for UDP connections::
+
+
+File: gnutls.info, Node: Client example with anonymous authentication, Next: Using a callback to select the certificate to use, Up: More advanced client and servers
+
+7.3.1 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 <assert.h>
+#include <gnutls/gnutls.h>
+
+/* A very basic TLS client, with anonymous authentication.
+ */
+
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
+ assert(rval >= 0)
+
+#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);
+ }
+
+ LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
+
+ LOOP_CHECK(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);
+ }
+
+ LOOP_CHECK(ret, 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: Using a callback to select the certificate to use, Next: Obtaining session information, Prev: Client example with anonymous authentication, Up: More advanced client and servers
+
+7.3.2 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 <assert.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 CHECK(x) assert((x)>=0)
+
+#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)
+{
+ gnutls_datum_t data;
+
+ CHECK(gnutls_load_file(CERT_FILE, &data));
+
+ CHECK(gnutls_pcert_import_x509_raw(&pcrt, &data,
+ GNUTLS_X509_FMT_PEM, 0));
+
+ gnutls_free(data.data);
+
+ CHECK(gnutls_load_file(KEY_FILE, &data));
+
+ CHECK(gnutls_privkey_init(&key));
+
+ CHECK(gnutls_privkey_import_x509_raw(key, &data,
+ GNUTLS_X509_FMT_PEM,
+ NULL, 0));
+ gnutls_free(data.data);
+}
+
+int main(void)
+{
+ int ret, sd, ii;
+ gnutls_session_t session;
+ 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 */
+ CHECK(gnutls_global_init());
+
+ load_keys();
+
+ /* X509 stuff */
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+
+ /* sets the trusted cas file
+ */
+ CHECK(gnutls_certificate_set_x509_trust_file(xcred, CAFILE,
+ GNUTLS_X509_FMT_PEM));
+
+ gnutls_certificate_set_retrieve_function2(xcred, cert_callback);
+
+ /* Initialize TLS session
+ */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ /* Use default priorities */
+ CHECK(gnutls_set_default_priority(session));
+
+ /* put the x509 credentials to the current session
+ */
+ CHECK(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);
+ }
+
+ CHECK(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);
+
+ CHECK(gnutls_bye(session, GNUTLS_SHUT_RDWR));
+
+ end:
+
+ tcp_close(sd);
+
+ gnutls_deinit(session);
+
+ gnutls_certificate_free_credentials(xcred);
+
+ 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: Obtaining session information, Next: Advanced certificate verification example, Prev: Using a callback to select the certificate to use, Up: More advanced client and servers
+
+7.3.3 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)
+{
+ gnutls_credentials_type_t cred;
+ gnutls_kx_algorithm_t kx;
+ int dhe, ecdh, group;
+ char *desc;
+
+ /* get a description of the session connection, protocol,
+ * cipher/key exchange */
+ desc = gnutls_session_get_desc(session);
+ if (desc != NULL) {
+ printf("- Session: %s\n", desc);
+ }
+
+ dhe = ecdh = 0;
+
+ kx = gnutls_kx_get(session);
+
+ /* Check the authentication type used and switch
+ * to the appropriate.
+ */
+ cred = gnutls_auth_get_type(session);
+ switch (cred) {
+#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);
+ break;
+ default:
+ break;
+ } /* switch */
+
+ /* read the negotiated group - if any */
+ group = gnutls_group_get(session);
+ if (group != 0) {
+ printf("- Negotiated group %s\n",
+ gnutls_group_get_name(group));
+ } else {
+ 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));
+ }
+
+ return 0;
+}
+
+
+File: gnutls.info, Node: Advanced certificate verification example, Next: Client example with PSK authentication, Prev: Obtaining session information, Up: More advanced client and servers
+
+7.3.4 Advanced certificate verification
+---------------------------------------
+
+An example is listed below which uses the high level verification
+functions to verify a given certificate chain against a set of CAs and
+CRLs.
+
+/* 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 <assert.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "examples.h"
+
+#define CHECK(x) assert((x)>=0)
+
+/* 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;
+ gnutls_datum_t txt;
+ 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.
+ */
+ CHECK(gnutls_x509_trust_list_init(&tlist, 0));
+
+ CHECK(gnutls_x509_trust_list_add_cas(tlist, ca_list, ca_list_size, 0));
+ CHECK(gnutls_x509_trust_list_add_crls(tlist, crl_list, crl_list_size,
+ GNUTLS_TL_VERIFY_CRL, 0));
+
+ cert = gnutls_calloc(cert_chain_length, sizeof(*cert));
+ assert(cert != NULL);
+
+ /* Import all the certificates in the chain to
+ * native certificate format.
+ */
+ for (i = 0; i < cert_chain_length; i++) {
+ CHECK(gnutls_x509_crt_init(&cert[i]));
+ CHECK(gnutls_x509_crt_import(cert[i], &cert_chain[i],
+ GNUTLS_X509_FMT_DER));
+ }
+
+ CHECK(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) {
+ CHECK(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\n");
+ CHECK(gnutls_certificate_verification_status_print(
+ output,
+ GNUTLS_CRT_X509,
+ &txt, 0));
+
+ fprintf(stderr, "Error: %s\n", txt.data);
+ gnutls_free(txt.data);
+ } 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);
+ }
+
+ for (i = 0; i < cert_chain_length; i++) {
+ gnutls_x509_crt_deinit(cert[i]);
+ }
+ gnutls_free(cert);
+
+ 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 example with PSK authentication, Next: Client example with SRP authentication, Prev: Advanced certificate verification example, Up: More advanced client and servers
+
+7.3.5 Client example with PSK authentication
+--------------------------------------------
+
+The following client is a very simple PSK TLS client which connects to a
+server and authenticates using a _username_ and a _key_.
+
+/* 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 <assert.h>
+#include <gnutls/gnutls.h>
+
+/* A very basic TLS client, with PSK authentication.
+ */
+
+#define CHECK(x) assert((x)>=0)
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
+ assert(rval >= 0)
+
+#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];
+ const char *err;
+ gnutls_psk_client_credentials_t pskcred;
+ const gnutls_datum_t key = { (void *) "DEADBEEF", 8 };
+
+ if (gnutls_check_version("3.6.3") == NULL) {
+ fprintf(stderr, "GnuTLS 3.6.3 or later is required for this example\n");
+ exit(1);
+ }
+
+ CHECK(gnutls_global_init());
+
+ CHECK(gnutls_psk_allocate_client_credentials(&pskcred));
+ CHECK(gnutls_psk_set_client_credentials(pskcred, "test", &key,
+ GNUTLS_PSK_KEY_HEX));
+
+ /* Initialize TLS session
+ */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ ret =
+ gnutls_set_default_priority_append(session,
+ "-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK",
+ &err, 0);
+
+ /* Alternative for pre-3.6.3 versions:
+ * gnutls_priority_set_direct(session, "NORMAL:+ECDHE-PSK:+DHE-PSK:+PSK", &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
+ */
+ CHECK(gnutls_credentials_set(session, GNUTLS_CRD_PSK, pskcred));
+
+ /* 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);
+ }
+
+ LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
+
+ LOOP_CHECK(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);
+ }
+
+ CHECK(gnutls_bye(session, GNUTLS_SHUT_RDWR));
+
+ end:
+
+ tcp_close(sd);
+
+ gnutls_deinit(session);
+
+ gnutls_psk_free_client_credentials(pskcred);
+
+ gnutls_global_deinit();
+
+ return 0;
+}
+
+
+File: gnutls.info, Node: Client example with SRP authentication, Next: Legacy client example with X.509 certificate support, Prev: Client example with PSK authentication, Up: More advanced client and servers
+
+7.3.6 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: Legacy client example with X.509 certificate support, Next: Client example in C++, Prev: Client example with SRP authentication, Up: More advanced client and servers
+
+7.3.7 Legacy client example with X.509 certificate support
+----------------------------------------------------------
+
+For applications that need to maintain compatibility with the GnuTLS
+3.1.x library, this client example is identical to *note Client example
+with X.509 certificate support:: but utilizes APIs that were available
+in GnuTLS 3.1.4.
+
+/* 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 <assert.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 utilizing the GnuTLS 3.1.x API.
+ * Note that error recovery is minimal for simplicity.
+ */
+
+#define CHECK(x) assert((x)>=0)
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED); \
+ assert(rval >= 0)
+
+#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];
+ 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);
+ }
+
+ CHECK(gnutls_global_init());
+
+ /* X509 stuff */
+ CHECK(gnutls_certificate_allocate_credentials(&xcred));
+
+ /* sets the trusted cas file
+ */
+ CHECK(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
+ */
+ CHECK(gnutls_init(&session, GNUTLS_CLIENT));
+
+ gnutls_session_set_ptr(session, (void *) "www.example.com");
+
+ gnutls_server_name_set(session, GNUTLS_NAME_DNS, "www.example.com",
+ strlen("www.example.com"));
+
+ /* use default priorities */
+ CHECK(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
+ */
+ CHECK(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);
+ }
+
+ LOOP_CHECK(ret, gnutls_record_send(session, MSG, strlen(MSG)));
+
+ LOOP_CHECK(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);
+ }
+
+ CHECK(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 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.
+ */
+
+ CHECK(gnutls_certificate_verify_peers3(session, hostname,
+ &status));
+
+ type = gnutls_certificate_type_get(session);
+
+ CHECK(gnutls_certificate_verification_status_print(status, type,
+ &out, 0));
+
+ 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: Client example in C++, Next: Echo server with PSK authentication, Prev: Legacy client example with X.509 certificate support, Up: More advanced client and servers
+
+7.3.8 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: Echo server with PSK authentication, Next: Echo server with SRP authentication, Prev: Client example in C++, Up: More advanced client and servers
+
+7.3.9 Echo server with PSK authentication
+-----------------------------------------
+
+This is a server which supports PSK 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"
+
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
+
+/* This is a sample TLS echo server, supporting X.509 and PSK
+ authentication.
+ */
+
+#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}
+#define MAX_BUF 1024
+#define PORT 5556 /* listen to 5556 port */
+
+static int
+pskfunc(gnutls_session_t session, const char *username,
+ gnutls_datum_t * key)
+{
+ printf("psk: username %s\n", username);
+ key->data = gnutls_malloc(4);
+ key->data[0] = 0xDE;
+ key->data[1] = 0xAD;
+ key->data[2] = 0xBE;
+ key->data[3] = 0xEF;
+ key->size = 4;
+ 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 x509_cred;
+ gnutls_psk_server_credentials_t psk_cred;
+ gnutls_priority_t priority_cache;
+ char buffer[MAX_BUF + 1];
+ int optval = 1;
+ int kx;
+
+ 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(&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);
+
+ gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE,
+ GNUTLS_X509_FMT_PEM);
+
+ gnutls_psk_allocate_server_credentials(&psk_cred);
+ gnutls_psk_set_server_credentials_function(psk_cred, pskfunc);
+
+ /* pre-3.6.3 equivalent:
+ * gnutls_priority_init(&priority_cache,
+ * "NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK",
+ * NULL);
+ */
+ gnutls_priority_init2(&priority_cache,
+ "+ECDHE-PSK:+DHE-PSK:+PSK",
+ NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+
+ gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM);
+
+ /* 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(session, priority_cache);
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+ x509_cred);
+ gnutls_credentials_set(session, GNUTLS_CRD_PSK, psk_cred);
+
+ /* 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);
+ LOOP_CHECK(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");
+
+ kx = gnutls_kx_get(session);
+ if (kx == GNUTLS_KX_PSK || kx == GNUTLS_KX_DHE_PSK ||
+ kx == GNUTLS_KX_ECDHE_PSK) {
+ printf("- User %s was connected\n",
+ gnutls_psk_server_get_username(session));
+ }
+
+ /* see the Getting peer's information example */
+ /* print_info(session); */
+
+ for (;;) {
+ LOOP_CHECK(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.
+ */
+ LOOP_CHECK(ret, gnutls_bye(session, GNUTLS_SHUT_WR));
+
+ close(sd);
+ gnutls_deinit(session);
+
+ }
+ close(listen_sd);
+
+ gnutls_certificate_free_credentials(x509_cred);
+ gnutls_psk_free_server_credentials(psk_cred);
+
+ gnutls_priority_deinit(priority_cache);
+
+ gnutls_global_deinit();
+
+ return 0;
+
+}
+