diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
commit | 36082a2fe36ecd800d784ae44c14f1f18c66a7e9 (patch) | |
tree | 6c68e0c0097987aff85a01dabddd34b862309a7c /doc/gnutls.info-2 | |
parent | Initial commit. (diff) | |
download | gnutls28-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-2 | 7184 |
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; + +} + |