This is gnutls.info, produced by makeinfo version 5.2 from gnutls.texi. This manual is last updated 1 January 2014 for version 3.2.18 of GnuTLS. Copyright (C) 2001-2013 Free Software Foundation, Inc.\\ Copyright (C) 2001-2013 Nikos Mavrogiannopoulos Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Software libraries START-INFO-DIR-ENTRY * GnuTLS: (gnutls). GNU Transport Layer Security Library. END-INFO-DIR-ENTRY INFO-DIR-SECTION System Administration START-INFO-DIR-ENTRY * certtool: (gnutls)Invoking certtool. Manipulate certificates and keys. * gnutls-serv: (gnutls)Invoking gnutls-serv. GnuTLS test server. * gnutls-cli: (gnutls)Invoking gnutls-cli. GnuTLS test client. * gnutls-cli-debug: (gnutls)Invoking gnutls-cli-debug. GnuTLS debug client. * psktool: (gnutls)Invoking psktool. Simple TLS-Pre-Shared-Keys manager. * srptool: (gnutls)Invoking srptool. Simple SRP password tool. END-INFO-DIR-ENTRY  File: gnutls.info, Node: Asynchronous operation, Next: DTLS sessions, Up: Setting up the transport layer 6.5.1 Asynchronous operation ---------------------------- GnuTLS can be used with asynchronous socket or event-driven programming. The approach is similar to using Berkeley sockets under such an environment. The blocking, due to network interaction, calls such as *note gnutls_handshake::, *note gnutls_record_recv::, can be set to non-blocking by setting the underlying sockets to non-blocking. If other push and pull functions are setup, then they should behave the same way as 'recv' and 'send' when used in a non-blocking way, i.e., set errno to 'EAGAIN'. Since, during a TLS protocol session GnuTLS does not block except for network interaction, the non blocking 'EAGAIN' errno will be propagated and GnuTLS functions will return the 'GNUTLS_E_AGAIN' error code. Such calls can be resumed the same way as a system call would. The only exception is *note gnutls_record_send::, which if interrupted subsequent calls need not to include the data to be sent (can be called with NULL argument). The 'select' system call can also be used in combination with the GnuTLS functions. 'select' allows monitoring of sockets and notifies on them being ready for reading or writing data. Note however that this system call cannot notify on data present in GnuTLS read buffers, it is only applicable to the kernel sockets API. Thus if you are using it for reading from a GnuTLS session, make sure that any cached data are read completely. That can be achieved by checking there are no data waiting to be read (using *note gnutls_record_check_pending::), either before the 'select' system call, or after a call to *note gnutls_record_recv::. GnuTLS does not keep a write buffer, thus when writing no additional actions are required. Although in the TLS protocol implementation each call to receive or send function implies to restoring the same function that was interrupted, in the DTLS protocol this requirement isn't true. There are cases where a retransmission is required, which are indicated by a received message and thus *note gnutls_record_get_direction:: must be called to decide which direction to check prior to restoring a function call. -- Function: int gnutls_record_get_direction (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. This function provides information about the internals of the record protocol and is only useful if a prior gnutls function call (e.g. 'gnutls_handshake()' ) was interrupted for some reason, that is, if a function returned 'GNUTLS_E_INTERRUPTED' or 'GNUTLS_E_AGAIN' . In such a case, you might want to call 'select()' or 'poll()' before calling the interrupted gnutls function again. To tell you whether a file descriptor should be selected for either reading or writing, 'gnutls_record_get_direction()' returns 0 if the interrupted function was trying to read data, and 1 if it was trying to write data. *Returns:* 0 if trying to read data, 1 if trying to write data. Moreover, to prevent blocking from DTLS' retransmission timers to block a handshake, the *note gnutls_init:: function should be called with the 'GNUTLS_NONBLOCK' flag set (see *note Session initialization::). In that case, in order to be able to use the DTLS handshake timers, the function *note gnutls_dtls_get_timeout:: should be used to estimate when to call *note gnutls_handshake:: if no packets have been received.  File: gnutls.info, Node: DTLS sessions, Prev: Asynchronous operation, Up: Setting up the transport layer 6.5.2 DTLS sessions ------------------- Because datagram TLS can operate over connections where the client cannot be reliably verified, functionality in the form of cookies, is available to prevent denial of service attacks to servers. GnuTLS requires a server to generate a secret key that is used to sign a cookie(1). That cookie is sent to the client using *note gnutls_dtls_cookie_send::, and the client must reply using the correct cookie. The server side should verify the initial message sent by client using *note gnutls_dtls_cookie_verify::. If successful the session should be initialized and associated with the cookie using *note gnutls_dtls_prestate_set::, before proceeding to the handshake. 'INT *note gnutls_key_generate:: (gnutls_datum_t * KEY, unsigned int KEY_SIZE)' 'INT *note gnutls_dtls_cookie_send:: (gnutls_datum_t * KEY, void * CLIENT_DATA, size_t CLIENT_DATA_SIZE, gnutls_dtls_prestate_st * PRESTATE, gnutls_transport_ptr_t PTR, gnutls_push_func PUSH_FUNC)' 'INT *note gnutls_dtls_cookie_verify:: (gnutls_datum_t * KEY, void * CLIENT_DATA, size_t CLIENT_DATA_SIZE, void * _MSG, size_t MSG_SIZE, gnutls_dtls_prestate_st * PRESTATE)' 'VOID *note gnutls_dtls_prestate_set:: (gnutls_session_t SESSION, gnutls_dtls_prestate_st * PRESTATE)' Note that the above apply to server side only and they are not mandatory to be used. Not using them, however, allows denial of service attacks. The client side cookie handling is part of *note gnutls_handshake::. Datagrams are typically restricted by a maximum transfer unit (MTU). For that both client and server side should set the correct maximum transfer unit for the layer underneath GnuTLS. This will allow proper fragmentation of DTLS messages and prevent messages from being silently discarded by the transport layer. The "correct" maximum transfer unit can be obtained through a path MTU discovery mechanism [_RFC4821_]. 'VOID *note gnutls_dtls_set_mtu:: (gnutls_session_t SESSION, unsigned int MTU)' 'UNSIGNED INT *note gnutls_dtls_get_mtu:: (gnutls_session_t SESSION)' 'UNSIGNED INT *note gnutls_dtls_get_data_mtu:: (gnutls_session_t SESSION)' ---------- Footnotes ---------- (1) A key of 128 bits or 16 bytes should be sufficient for this purpose.  File: gnutls.info, Node: TLS handshake, Next: Data transfer and termination, Prev: Setting up the transport layer, Up: How to use GnuTLS in applications 6.6 TLS handshake ================= Once a session has been initialized and a network connection has been set up, TLS and DTLS protocols perform a handshake. The handshake is the actual key exchange. -- Function: int gnutls_handshake (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. This function does the handshake of the TLS/SSL protocol, and initializes the TLS connection. This function will fail if any problem is encountered, and will return a negative error code. In case of a client, if the client has asked to resume a session, but the server couldn't, then a full handshake will be performed. The non-fatal errors such as 'GNUTLS_E_AGAIN' and 'GNUTLS_E_INTERRUPTED' interrupt the handshake procedure, which should be resumed later. Call this function again, until it returns 0; cf. 'gnutls_record_get_direction()' and 'gnutls_error_is_fatal()' . If this function is called by a server after a rehandshake request then 'GNUTLS_E_GOT_APPLICATION_DATA' or 'GNUTLS_E_WARNING_ALERT_RECEIVED' may be returned. Note that these are non fatal errors, only in the specific case of a rehandshake. Their meaning is that the client rejected the rehandshake request or in the case of 'GNUTLS_E_GOT_APPLICATION_DATA' it might also mean that some data were pending. *Returns:* 'GNUTLS_E_SUCCESS' on success, otherwise a negative error code. -- Function: void gnutls_handshake_set_timeout (gnutls_session_t SESSION, unsigned int MS) SESSION: is a 'gnutls_session_t' structure. MS: is a timeout value in milliseconds This function sets the timeout for the handshake process to the provided value. Use an 'ms' value of zero to disable timeout. Note that in order for the timeout to be enforced 'gnutls_transport_set_pull_timeout_function()' must be set (it is set by default in most systems). The handshake process doesn't ensure the verification of the peer's identity. When certificates are in use, this can be done, either after the handshake is complete, or during the handshake if *note gnutls_certificate_set_verify_function:: has been used. In both cases the *note gnutls_certificate_verify_peers2:: function can be used to verify the peer's certificate (see *note Certificate authentication:: for more information). 'INT *note gnutls_certificate_verify_peers2:: (gnutls_session_t SESSION, unsigned int * STATUS)'  File: gnutls.info, Node: Data transfer and termination, Next: Buffered data transfer, Prev: TLS handshake, Up: How to use GnuTLS in applications 6.7 Data transfer and termination ================================= Once the handshake is complete and peer's identity has been verified data can be exchanged. The available functions resemble the POSIX 'recv' and 'send' functions. It is suggested to use *note gnutls_error_is_fatal:: to check whether the error codes returned by these functions are fatal for the protocol or can be ignored. -- Function: ssize_t gnutls_record_send (gnutls_session_t SESSION, const void * DATA, size_t DATA_SIZE) SESSION: is a 'gnutls_session_t' structure. DATA: contains the data to send DATA_SIZE: is the length of the data This function has the similar semantics with 'send()' . The only difference is that it accepts a GnuTLS session, and uses different error codes. Note that if the send buffer is full, 'send()' will block this function. See the 'send()' documentation for more information. You can replace the default push function which is 'send()' , by using 'gnutls_transport_set_push_function()' . If the EINTR is returned by the internal push function then 'GNUTLS_E_INTERRUPTED' will be returned. If 'GNUTLS_E_INTERRUPTED' or 'GNUTLS_E_AGAIN' is returned, you must call this function again, with the exact same parameters; alternatively you could provide a 'NULL' pointer for data, and 0 for size. cf. 'gnutls_record_get_direction()' . Note that in DTLS this function will return the 'GNUTLS_E_LARGE_PACKET' error code if the send data exceed the data MTU value - as returned by 'gnutls_dtls_get_data_mtu()' . The errno value EMSGSIZE also maps to 'GNUTLS_E_LARGE_PACKET' . Note that since 3.2.13 this function can be called under cork in DTLS mode, and will refuse to send data over the MTU size by returning 'GNUTLS_E_LARGE_PACKET' . *Returns:* The number of bytes sent, or a negative error code. The number of bytes sent might be less than 'data_size' . The maximum number of bytes this function can send in a single call depends on the negotiated maximum record size. -- Function: ssize_t gnutls_record_recv (gnutls_session_t SESSION, void * DATA, size_t DATA_SIZE) SESSION: is a 'gnutls_session_t' structure. DATA: the buffer that the data will be read into DATA_SIZE: the number of requested bytes This function has the similar semantics with 'recv()' . The only difference is that it accepts a GnuTLS session, and uses different error codes. In the special case that a server requests a renegotiation, the client may receive an error code of 'GNUTLS_E_REHANDSHAKE' . This message may be simply ignored, replied with an alert 'GNUTLS_A_NO_RENEGOTIATION' , or replied with a new handshake, depending on the client's will. If 'EINTR' is returned by the internal push function (the default is 'recv()' ) then 'GNUTLS_E_INTERRUPTED' will be returned. If 'GNUTLS_E_INTERRUPTED' or 'GNUTLS_E_AGAIN' is returned, you must call this function again to get the data. See also 'gnutls_record_get_direction()' . A server may also receive 'GNUTLS_E_REHANDSHAKE' when a client has initiated a handshake. In that case the server can only initiate a handshake or terminate the connection. *Returns:* The number of bytes received and zero on EOF (for stream connections). A negative error code is returned in case of an error. The number of bytes received might be less than the requested 'data_size' . -- Function: int gnutls_error_is_fatal (int ERROR) ERROR: is a GnuTLS error code, a negative error code If a GnuTLS function returns a negative error code you may feed that value to this function to see if the error condition is fatal to a TLS session (i.e., must be terminated). Note that you may also want to check the error code manually, since some non-fatal errors to the protocol (such as a warning alert or a rehandshake request) may be fatal for your program. This function is only useful if you are dealing with errors from functions that relate to a TLS session (e.g., record layer or handshake layer handling functions). *Returns:* zero on non fatal errors or positive 'error' values. Non-zero on fatal error codes. Although, in the TLS protocol the receive function can be called at any time, when DTLS is used the GnuTLS receive functions must be called once a message is available for reading, even if no data are expected. This is because in DTLS various (internal) actions may be required due to retransmission timers. Moreover, an extended receive function is shown below, which allows the extraction of the message's sequence number. Due to the unreliable nature of the protocol, this field allows distinguishing out-of-order messages. -- Function: ssize_t gnutls_record_recv_seq (gnutls_session_t SESSION, void * DATA, size_t DATA_SIZE, unsigned char * SEQ) SESSION: is a 'gnutls_session_t' structure. DATA: the buffer that the data will be read into DATA_SIZE: the number of requested bytes SEQ: is the packet's 64-bit sequence number. Should have space for 8 bytes. This function is the same as 'gnutls_record_recv()' , except that it returns in addition to data, the sequence number of the data. This is useful in DTLS where record packets might be received out-of-order. The returned 8-byte sequence number is an integer in big-endian format and should be treated as a unique message identification. *Returns:* The number of bytes received and zero on EOF. A negative error code is returned in case of an error. The number of bytes received might be less than 'data_size' . *Since:* 3.0 The *note gnutls_record_check_pending:: helper function is available to allow checking whether data are available to be read in a GnuTLS session buffers. Note that this function complements but does not replace 'select', i.e., *note gnutls_record_check_pending:: reports no data to be read, 'select' should be called to check for data in the network buffers. -- Function: size_t gnutls_record_check_pending (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. This function checks if there are unread data in the gnutls buffers. If the return value is non-zero the next call to 'gnutls_record_recv()' is guaranteed not to block. *Returns:* Returns the size of the data or zero. 'INT *note gnutls_record_get_direction:: (gnutls_session_t SESSION)' Once a TLS or DTLS session is no longer needed, it is recommended to use *note gnutls_bye:: to terminate the session. That way the peer is notified securely about the intention of termination, which allows distinguishing it from a malicious connection termination. A session can be deinitialized with the *note gnutls_deinit:: function. -- Function: int gnutls_bye (gnutls_session_t SESSION, gnutls_close_request_t HOW) SESSION: is a 'gnutls_session_t' structure. HOW: is an integer Terminates the current TLS/SSL connection. The connection should have been initiated using 'gnutls_handshake()' . 'how' should be one of 'GNUTLS_SHUT_RDWR' , 'GNUTLS_SHUT_WR' . In case of 'GNUTLS_SHUT_RDWR' the TLS session gets terminated and further receives and sends will be disallowed. If the return value is zero you may continue using the underlying transport layer. 'GNUTLS_SHUT_RDWR' sends an alert containing a close request and waits for the peer to reply with the same message. In case of 'GNUTLS_SHUT_WR' the TLS session gets terminated and further sends will be disallowed. In order to reuse the connection you should wait for an EOF from the peer. 'GNUTLS_SHUT_WR' sends an alert containing a close request. Note that not all implementations will properly terminate a TLS connection. Some of them, usually for performance reasons, will terminate only the underlying transport layer, and thus not distinguishing between a malicious party prematurely terminating the connection and normal termination. This function may also return 'GNUTLS_E_AGAIN' or 'GNUTLS_E_INTERRUPTED' ; cf. 'gnutls_record_get_direction()' . *Returns:* 'GNUTLS_E_SUCCESS' on success, or an error code, see function documentation for entire semantics. -- Function: void gnutls_deinit (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. This function clears all buffers associated with the 'session' . This function will also remove session data from the session database if the session was terminated abnormally.  File: gnutls.info, Node: Buffered data transfer, Next: Handling alerts, Prev: Data transfer and termination, Up: How to use GnuTLS in applications 6.8 Buffered data transfer ========================== Although *note gnutls_record_send:: is sufficient to transmit data to the peer, when many small chunks of data are to be transmitted it is inefficient and wastes bandwidth due to the TLS record overhead. In that case it is preferrable to combine the small chunks before transmission. The following functions provide that functionality. -- Function: void gnutls_record_cork (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. If called 'gnutls_record_send()' will no longer send partial records. All queued records will be sent when 'gnutls_uncork()' is called, or when the maximum record size is reached. This function is safe to use with DTLS after GnuTLS 3.2.13. *Since:* 3.1.9 -- Function: int gnutls_record_uncork (gnutls_session_t SESSION, unsigned int FLAGS) SESSION: is a 'gnutls_session_t' structure. FLAGS: Could be zero or 'GNUTLS_RECORD_WAIT' This resets the effect of 'gnutls_cork()' , and flushes any pending data. If the 'GNUTLS_RECORD_WAIT' flag is specified then this function will block until the data is sent or a fatal error occurs (i.e., the function will retry on 'GNUTLS_E_AGAIN' and 'GNUTLS_E_INTERRUPTED' ). If the flag 'GNUTLS_RECORD_WAIT' is not specified and the function is interrupted then the 'GNUTLS_E_AGAIN' or 'GNUTLS_E_INTERRUPTED' errors will be returned. To obtain the data left in the corked buffer use 'gnutls_record_check_corked()' . *Returns:* On success the number of transmitted data is returned, or otherwise a negative error code. *Since:* 3.1.9  File: gnutls.info, Node: Handling alerts, Next: Priority Strings, Prev: Buffered data transfer, Up: How to use GnuTLS in applications 6.9 Handling alerts =================== During a TLS connection alert messages may be exchanged by the two peers. Those messages may be fatal, meaning the connection must be terminated afterwards, or warning when something needs to be reported to the peer, but without interrupting the session. The error codes 'GNUTLS_E_WARNING_ALERT_RECEIVED' or 'GNUTLS_E_FATAL_ALERT_RECEIVED' signal those alerts when received, and may be returned by all GnuTLS functions that receive data from the peer, being *note gnutls_handshake:: and *note gnutls_record_recv::. If those error codes are received the alert and its level should be logged or reported to the peer using the functions below. -- Function: gnutls_alert_description_t gnutls_alert_get (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. This function will return the last alert number received. This function should be called when 'GNUTLS_E_WARNING_ALERT_RECEIVED' or 'GNUTLS_E_FATAL_ALERT_RECEIVED' errors are returned by a gnutls function. The peer may send alerts if he encounters an error. If no alert has been received the returned value is undefined. *Returns:* the last alert received, a 'gnutls_alert_description_t' value. -- Function: const char * gnutls_alert_get_name (gnutls_alert_description_t ALERT) ALERT: is an alert number. This function will return a string that describes the given alert number, or 'NULL' . See 'gnutls_alert_get()' . *Returns:* string corresponding to 'gnutls_alert_description_t' value. The peer may also be warned or notified of a fatal issue by using one of the functions below. All the available alerts are listed in *note The Alert Protocol::. -- Function: int gnutls_alert_send (gnutls_session_t SESSION, gnutls_alert_level_t LEVEL, gnutls_alert_description_t DESC) SESSION: is a 'gnutls_session_t' structure. LEVEL: is the level of the alert DESC: is the alert description This function will send an alert to the peer in order to inform him of something important (eg. his Certificate could not be verified). If the alert level is Fatal then the peer is expected to close the connection, otherwise he may ignore the alert and continue. The error code of the underlying record send function will be returned, so you may also receive 'GNUTLS_E_INTERRUPTED' or 'GNUTLS_E_AGAIN' as well. *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, otherwise an error code is returned. -- Function: int gnutls_error_to_alert (int ERR, int * LEVEL) ERR: is a negative integer LEVEL: the alert level will be stored there Get an alert depending on the error code returned by a gnutls function. All alerts sent by this function should be considered fatal. The only exception is when 'err' is 'GNUTLS_E_REHANDSHAKE' , where a warning alert should be sent to the peer indicating that no renegotiation will be performed. If there is no mapping to a valid alert the alert to indicate internal error is returned. *Returns:* the alert code to use for a particular error code.  File: gnutls.info, Node: Priority Strings, Next: Selecting cryptographic key sizes, Prev: Handling alerts, Up: How to use GnuTLS in applications 6.10 Priority strings ===================== The GnuTLS priority string specifies the TLS session's handshake algorithms and options in a compact, easy-to-use format. That string may contain a single initial keyword such as in *note Table 6.2: tab:prio-keywords. and may be followed by additional algorithm or special keywords. 'INT *note gnutls_priority_set_direct:: (gnutls_session_t SESSION, const char * PRIORITIES, const char ** ERR_POS)' 'INT *note gnutls_priority_set:: (gnutls_session_t SESSION, gnutls_priority_t PRIORITY)' Keyword Description ------------------------------------------------------------------ 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. 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. This priority string implicitly enables DHE and ECDHE. PFS Means all the known to be secure ciphersuites that support perfect forward secrecy. 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. 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 and a message authenticity security level of 80 bits or more. SECURE192 Means all the known to be secure ciphersuites that offer a security level 192-bit or more and a message authenticity security level of 128 bits or more. SECURE256 Currently alias for SECURE192. SUITEB128 Means all the NSA Suite B cryptography (RFC5430) ciphersuites with an 128 bit security level. SUITEB192 Means all the NSA Suite B cryptography (RFC5430) ciphersuites with an 192 bit security level. EXPORT Means all ciphersuites are enabled, including the low-security 40 bit ciphers. NONE Means nothing is enabled. This disables even protocols and compression methods. It should be followed by the algorithms to be enabled. Table 6.2: Supported initial keywords. Unless the initial keyword is "NONE" the defaults (in preference order) are for TLS protocols TLS 1.2, TLS1.1, TLS1.0, SSL3.0; for compression NULL; for certificate types X.509. In key exchange algorithms when in NORMAL or SECURE levels the perfect forward secrecy algorithms take precedence of the other protocols. In all cases all the supported key exchange algorithms are enabled. Note that the SECURE levels distinguish between overall security level and message authenticity security level. That is because the message authenticity security level requires the adversary to break the algorithms at real-time during the protocol run, whilst the overall security level refers to off-line adversaries (e.g. adversaries breaking the ciphertext years after it was captured). The NONE keyword, if used, must followed by keywords specifying the algorithms and protocols to be enabled. The other initial keywords do not require, but may be followed by such keywords. All level keywords can be combined, and for example a level of "SECURE256:+SECURE128" is allowed. The order with which every algorithm or protocol is specified is significant. Algorithms specified before others will take precedence. The supported algorithms and protocols are shown in *note Table 6.3: tab:prio-algorithms. To avoid collisions in order to specify a compression algorithm in the priority string you have to prefix it with "COMP-", protocol versions with "VERS-", signature algorithms with "SIGN-" and certificate types with "CTYPE-". All other algorithms don't need a prefix. Each specified keyword can be prefixed with any of the following characters. '!' or '-' appended with an algorithm will remove this algorithm. "+" appended with an algorithm will add this algorithm. Type Keywords ------------------------------------------------------------------ Ciphers AES-128-CBC, AES-256-CBC, AES-128-GCM, CAMELLIA-128-CBC, CAMELLIA-256-CBC, ARCFOUR-128, 3DES-CBC ARCFOUR-40. Catch all name is CIPHER-ALL which will add all the algorithms from NORMAL priority. Key exchange RSA, DHE-RSA, DHE-DSS, SRP, SRP-RSA, SRP-DSS, PSK, DHE-PSK, ECDHE-RSA, ANON-ECDH, ANON-DH. The Catch all name is KX-ALL which will add all the algorithms from NORMAL priority. Add '!DHE-RSA:!DHE-DSS' to the priority string to disable DHE. MAC MD5, SHA1, SHA256, SHA384, AEAD (used with GCM ciphers only). All algorithms from NORMAL priority can be accessed with MAC-ALL. Compression COMP-NULL, COMP-DEFLATE. Catch all is COMP-ALL. algorithms TLS versions VERS-SSL3.0, VERS-TLS1.0, VERS-TLS1.1, VERS-TLS1.2, VERS-DTLS1.2, VERS-DTLS1.0. Catch all is VERS-TLS-ALL and VERS-DTLS-ALL. Signature SIGN-RSA-SHA1, SIGN-RSA-SHA224, SIGN-RSA-SHA256, algorithms SIGN-RSA-SHA384, SIGN-RSA-SHA512, SIGN-DSA-SHA1, SIGN-DSA-SHA224, SIGN-DSA-SHA256, SIGN-RSA-MD5. Catch all is SIGN-ALL. This is only valid for TLS 1.2 and later. Elliptic CURVE-SECP192R1, CURVE-SECP224R1, curves CURVE-SECP256R1, CURVE-SECP384R1, CURVE-SECP521R1. Catch all is CURVE-ALL. Table 6.3: The supported algorithm keywords in priority strings. Note that the DHE key exchange methods are generally slower(1) than their elliptic curves counterpart (ECDHE). Moreover the plain Diffie-Hellman key exchange requires parameters to be generated and associated with a credentials structure by the server (see *note Parameter generation::). The available special keywords are shown in *note Table 6.4: tab:prio-special1. and *note Table 6.5: tab:prio-special2. Keyword Description ------------------------------------------------------------------ %COMPAT will enable compatibility mode. It might mean that violations of the protocols are allowed as long as maximum compatibility with problematic clients and servers is achieved. More specifically this string would disable TLS record random padding, tolerate packets over the maximum allowed TLS record, and add a padding to TLS Client Hello packet to prevent it being in the 256-512 range which is known to be causing issues with a commonly used firewall. %DUMBFW will add a private extension with bogus data that make the client hello exceed 512 bytes. This avoids a black hole behavior in some firewalls. This is a non-standard TLS extension, use with care. %NO_EXTENSIONS will prevent the sending of any TLS extensions in client side. Note that TLS 1.2 requires extensions to be used, as well as safe renegotiation thus this option must be used with care. %SERVER_PRECEDENCE The ciphersuite will be selected according to server priorities and not the client's. %SSL3_RECORD_VERSION will use SSL3.0 record version in client hello. This is the default. %LATEST_RECORD_VERSION will use the latest TLS version record version in client hello. Table 6.4: Special priority string keywords. Keyword Description ------------------------------------------------------------------ %STATELESS_COMPRESSION will disable keeping state across records when compressing. This may help to mitigate attacks when compression is used but an attacker is in control of input data. This has to be used only when the data that are possibly controlled by an attacker are placed in separate records. %DISABLE_SAFE_RENEGOTIATION will completely disable safe renegotiation completely. Do not use unless you know what you are doing. %UNSAFE_RENEGOTIATION will allow handshakes and re-handshakes without the safe renegotiation extension. Note that for clients this mode is insecure (you may be under attack), and for servers it will allow insecure clients to connect (which could be fooled by an attacker). Do not use unless you know what you are doing and want maximum compatibility. %PARTIAL_RENEGOTIATION will allow initial handshakes to proceed, but not re-handshakes. This leaves the client vulnerable to attack, and servers will be compatible with non-upgraded clients for initial handshakes. This is currently the default for clients and servers, for compatibility reasons. %SAFE_RENEGOTIATION will enforce safe renegotiation. Clients and servers will refuse to talk to an insecure peer. Currently this causes interoperability problems, but is required for full protection. %VERIFY_ALLOW_SIGN_RSA_MD5 will allow RSA-MD5 signatures in certificate chains. %VERIFY_DISABLE_CRL_CHECKS will disable CRL or OCSP checks in the verification of the certificate chain. %VERIFY_ALLOW_X509_V1_CA_CRT will allow V1 CAs in chains. Table 6.5: 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 default priority without the HMAC-MD5: "NORMAL:-MD5" Specifying RSA with AES-128-CBC: "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL" Specifying the defaults except ARCFOUR-128: "NORMAL:-ARCFOUR-128" Enabling the 128-bit secure ciphers, while disabling SSL 3.0 and enabling compression: "SECURE128:-VERS-SSL3.0:+COMP-DEFLATE" Enabling the 128-bit and 192-bit secure ciphers, while disabling all TLS versions except TLS 1.2: "SECURE128:+SECURE192:-VERS-TLS-ALL:+VERS-TLS1.2" ---------- Footnotes ---------- (1) It depends on the group used. Primes with lesser bits are always faster, but also easier to break. See *note Selecting cryptographic key sizes:: for the acceptable security levels.  File: gnutls.info, Node: Selecting cryptographic key sizes, Next: Advanced topics, Prev: Priority Strings, Up: How to use GnuTLS in applications 6.11 Selecting cryptographic key sizes ====================================== Because many algorithms are involved in TLS, it is not easy to set a consistent security level. For this reason in *note Table 6.6: tab:key-sizes. we present some correspondence between key sizes of symmetric algorithms and public key algorithms based on [_ECRYPT_]. Those can be used to generate certificates with appropriate key sizes as well as select parameters for Diffie-Hellman and SRP authentication. SecurityRSA, DH ECC Security Description bits and SRP key parameter parameter size size ----------------------------------------------------------------- <72 <1008 <160 'INSECURE' Considered to be insecure 72 1008 160 'WEAK' Short term protection against small organizations 80 1248 160 'LOW' Very short term protection against agencies 96 1776 192 'LEGACY' Legacy standard level 112 2432 224 'NORMAL' Medium-term protection 128 3248 256 'HIGH' Long term protection 256 15424 512 'ULTRA' Foreseeable future Table 6.6: Key sizes and security parameters. The first column provides a security parameter in a number of bits. This gives an indication of the number of combinations to be tried by an adversary to brute force a key. For example to test all possible keys in a 112 bit security parameter 2^{112} combinations have to be tried. For today's technology this is infeasible. The next two columns correlate the security parameter with actual bit sizes of parameters for DH, RSA, SRP and ECC algorithms. A mapping to 'gnutls_sec_param_t' value is given for each security parameter, on the next column, and finally a brief description of the level. Note, however, that the values suggested here are nothing more than an educated guess that is valid today. There are no guarantees that an algorithm will remain unbreakable or that these values will remain constant in time. There could be scientific breakthroughs that cannot be predicted or total failure of the current public key systems by quantum computers. On the other hand though the cryptosystems used in TLS are selected in a conservative way and such catastrophic breakthroughs or failures are believed to be unlikely. The NIST publication SP 800-57 [_NISTSP80057_] contains a similar table. When using GnuTLS and a decision on bit sizes for a public key algorithm is required, use of the following functions is recommended: -- Function: unsigned int gnutls_sec_param_to_pk_bits (gnutls_pk_algorithm_t ALGO, gnutls_sec_param_t PARAM) ALGO: is a public key algorithm PARAM: is a security parameter When generating private and public key pairs a difficult question is which size of "bits" the modulus will be in RSA and the group size in DSA. The easy answer is 1024, which is also wrong. This function will convert a human understandable security parameter to an appropriate size for the specific algorithm. *Returns:* The number of bits, or (0). *Since:* 2.12.0 -- Function: gnutls_sec_param_t gnutls_pk_bits_to_sec_param (gnutls_pk_algorithm_t ALGO, unsigned int BITS) ALGO: is a public key algorithm BITS: is the number of bits This is the inverse of 'gnutls_sec_param_to_pk_bits()' . Given an algorithm and the number of bits, it will return the security parameter. This is a rough indication. *Returns:* The security parameter. *Since:* 2.12.0 Those functions will convert a human understandable security parameter of 'gnutls_sec_param_t' type, to a number of bits suitable for a public key algorithm. 'CONST CHAR * *note gnutls_sec_param_get_name:: (gnutls_sec_param_t PARAM)' The following functions will set the minimum acceptable group size for Diffie-Hellman and SRP authentication. 'VOID *note gnutls_dh_set_prime_bits:: (gnutls_session_t SESSION, unsigned int BITS)' 'VOID *note gnutls_srp_set_prime_bits:: (gnutls_session_t SESSION, unsigned int BITS)'  File: gnutls.info, Node: Advanced topics, Prev: Selecting cryptographic key sizes, Up: How to use GnuTLS in applications 6.12 Advanced topics ==================== * Menu: * Session resumption:: * Certificate verification:: * Parameter generation:: * Deriving keys for other applications/protocols:: * Channel Bindings:: * Interoperability:: * Compatibility with the OpenSSL library::  File: gnutls.info, Node: Session resumption, Next: Certificate verification, Up: Advanced topics 6.12.1 Session resumption ------------------------- Client side ........... To reduce time and roundtrips spent in a handshake the client can request session resumption from a server that previously shared a session with the client. For that the client has to retrieve and store the session parameters. Before establishing a new session to the same server the parameters must be re-associated with the GnuTLS session using *note gnutls_session_set_data::. 'INT *note gnutls_session_get_data2:: (gnutls_session_t SESSION, gnutls_datum_t * DATA)' 'INT *note gnutls_session_get_id2:: (gnutls_session_t SESSION, gnutls_datum_t * SESSION_ID)' 'INT *note gnutls_session_set_data:: (gnutls_session_t SESSION, const void * SESSION_DATA, size_t SESSION_DATA_SIZE)' Keep in mind that sessions will be expired after some time, depending on the server, and a server may choose not to resume a session even when requested to. The expiration is to prevent temporal session keys from becoming long-term keys. Also note that as a client you must enable, using the priority functions, at least the algorithms used in the last session. -- Function: int gnutls_session_is_resumed (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. Check whether session is resumed or not. *Returns:* non zero if this session is resumed, or a zero if this is a new session. Server side ........... In order to support resumption a server can store the session security parameters in a local database or by using session tickets (see *note Session tickets::) to delegate storage to the client. Because session tickets might not be supported by all clients, servers could combine the two methods. A storing server needs to specify callback functions to store, retrieve and delete session data. These can be registered with the functions below. The stored sessions in the database can be checked using *note gnutls_db_check_entry:: for expiration. 'VOID *note gnutls_db_set_retrieve_function:: (gnutls_session_t SESSION, gnutls_db_retr_func RETR_FUNC)' 'VOID *note gnutls_db_set_store_function:: (gnutls_session_t SESSION, gnutls_db_store_func STORE_FUNC)' 'VOID *note gnutls_db_set_ptr:: (gnutls_session_t SESSION, void * PTR)' 'VOID *note gnutls_db_set_remove_function:: (gnutls_session_t SESSION, gnutls_db_remove_func REM_FUNC)' 'INT *note gnutls_db_check_entry:: (gnutls_session_t SESSION, gnutls_datum_t SESSION_ENTRY)' A server utilizing tickets should generate ticket encryption and authentication keys using *note gnutls_session_ticket_key_generate::. Those keys should be associated with the GnuTLS session using *note gnutls_session_ticket_enable_server::. -- Function: int gnutls_session_ticket_enable_server (gnutls_session_t SESSION, const gnutls_datum_t * KEY) SESSION: is a 'gnutls_session_t' structure. KEY: key to encrypt session parameters. Request that the server should attempt session resumption using SessionTicket. 'key' must be initialized with 'gnutls_session_ticket_key_generate()' . *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, or an error code. *Since:* 2.10.0 -- Function: int gnutls_session_ticket_key_generate (gnutls_datum_t * KEY) KEY: is a pointer to a 'gnutls_datum_t' which will contain a newly created key. Generate a random key to encrypt security parameters within SessionTicket. *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, or an error code. *Since:* 2.10.0 -- Function: int gnutls_session_resumption_requested (gnutls_session_t SESSION) SESSION: is a 'gnutls_session_t' structure. Check whether the client has asked for session resumption. This function is valid only on server side. *Returns:* non zero if session resumption was asked, or a zero if not. A server enabling both session tickets and a storage for session data would use session tickets when clients support it and the storage otherwise.  File: gnutls.info, Node: Certificate verification, Next: Parameter generation, Prev: Session resumption, Up: Advanced topics 6.12.2 Certificate verification ------------------------------- In this section the functionality for additional certificate verification methods is listed. These methods are intended to be used in addition to normal PKI verification, in order to reduce the risk of a compromised CA being undetected. 6.12.2.1 Trust on first use ........................... The GnuTLS library includes functionlity to use an SSH-like trust on first use authentication. The available functions to store and verify public keys are listed below. -- Function: int gnutls_verify_stored_pubkey (const char * DB_NAME, gnutls_tdb_t TDB, const char * HOST, const char * SERVICE, gnutls_certificate_type_t CERT_TYPE, const gnutls_datum_t * CERT, unsigned int FLAGS) DB_NAME: A file specifying the stored keys (use NULL for the default) TDB: A storage structure or NULL to use the default HOST: The peer's name SERVICE: non-NULL if this key is specific to a service (e.g. http) CERT_TYPE: The type of the certificate CERT: The raw (der) data of the certificate FLAGS: should be 0. This function will try to verify the provided certificate using a list of stored public keys. The 'service' field if non-NULL should be a port number. The 'retrieve' variable if non-null specifies a custom backend for the retrieval of entries. If it is NULL then the default file backend will be used. In POSIX-like systems the file backend uses the $HOME/.gnutls/known_hosts file. Note that if the custom storage backend is provided the retrieval function should return 'GNUTLS_E_CERTIFICATE_KEY_MISMATCH' if the host/service pair is found but key doesn't match, 'GNUTLS_E_NO_CERTIFICATE_FOUND' if no such host/service with the given key is found, and 0 if it was found. The storage function should return 0 on success. *Returns:* If no associated public key is found then 'GNUTLS_E_NO_CERTIFICATE_FOUND' will be returned. If a key is found but does not match 'GNUTLS_E_CERTIFICATE_KEY_MISMATCH' is returned. On success, 'GNUTLS_E_SUCCESS' (0) is returned, or a negative error value on other errors. *Since:* 3.0 -- Function: int gnutls_store_pubkey (const char * DB_NAME, gnutls_tdb_t TDB, const char * HOST, const char * SERVICE, gnutls_certificate_type_t CERT_TYPE, const gnutls_datum_t * CERT, time_t EXPIRATION, unsigned int FLAGS) DB_NAME: A file specifying the stored keys (use NULL for the default) TDB: A storage structure or NULL to use the default HOST: The peer's name SERVICE: non-NULL if this key is specific to a service (e.g. http) CERT_TYPE: The type of the certificate CERT: The data of the certificate EXPIRATION: The expiration time (use 0 to disable expiration) FLAGS: should be 0. This function will store the provided certificate to the list of stored public keys. The key will be considered valid until the provided expiration time. The 'store' variable if non-null specifies a custom backend for the storage of entries. If it is NULL then the default file backend will be used. *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, otherwise a negative error value. *Since:* 3.0 In addition to the above the *note gnutls_store_commitment:: can be used to implement a key-pinning architecture as in [_KEYPIN_]. This provides a way for web server to commit on a public key that is not yet active. -- Function: int gnutls_store_commitment (const char * DB_NAME, gnutls_tdb_t TDB, const char * HOST, const char * SERVICE, gnutls_digest_algorithm_t HASH_ALGO, const gnutls_datum_t * HASH, time_t EXPIRATION, unsigned int FLAGS) DB_NAME: A file specifying the stored keys (use NULL for the default) TDB: A storage structure or NULL to use the default HOST: The peer's name SERVICE: non-NULL if this key is specific to a service (e.g. http) HASH_ALGO: The hash algorithm type HASH: The raw hash EXPIRATION: The expiration time (use 0 to disable expiration) FLAGS: should be 0. This function will store the provided hash commitment to the list of stored public keys. The key with the given hash will be considered valid until the provided expiration time. The 'store' variable if non-null specifies a custom backend for the storage of entries. If it is NULL then the default file backend will be used. Note that this function is not thread safe with the default backend. *Returns:* On success, 'GNUTLS_E_SUCCESS' (0) is returned, otherwise a negative error value. *Since:* 3.0 The storage and verification functions may be used with the default text file based back-end, or another back-end may be specified. That should contain storage and retrieval functions and specified as below. 'INT *note gnutls_tdb_init:: (gnutls_tdb_t * TDB)' 'VOID *note gnutls_tdb_deinit:: (gnutls_tdb_t TDB)' 'VOID *note gnutls_tdb_set_verify_func:: (gnutls_tdb_t TDB, gnutls_tdb_verify_func VERIFY)' 'VOID *note gnutls_tdb_set_store_func:: (gnutls_tdb_t TDB, gnutls_tdb_store_func STORE)' 'VOID *note gnutls_tdb_set_store_commitment_func:: (gnutls_tdb_t TDB, gnutls_tdb_store_commitment_func CSTORE)' 6.12.2.2 DANE verification .......................... Since the DANE library is not included in GnuTLS it requires programs to be linked against it. This can be achieved with the following commands. gcc -o foo foo.c `pkg-config gnutls-dane --cflags --libs` When a program uses the GNU autoconf system, then the following line or similar can be used to detect the presence of the library. PKG_CHECK_MODULES([LIBDANE], [gnutls-dane >= 3.0.0]) AC_SUBST([LIBDANE_CFLAGS]) AC_SUBST([LIBDANE_LIBS]) The high level functionality provided by the DANE library is shown below. -- Function: int dane_verify_crt (dane_state_t S, const gnutls_datum_t * CHAIN, unsigned CHAIN_SIZE, gnutls_certificate_type_t CHAIN_TYPE, const char * HOSTNAME, const char * PROTO, unsigned int PORT, unsigned int SFLAGS, unsigned int VFLAGS, unsigned int * VERIFY) S: A DANE state structure (may be NULL) CHAIN: A certificate chain CHAIN_SIZE: The size of the chain CHAIN_TYPE: The type of the certificate chain HOSTNAME: The hostname associated with the chain PROTO: The protocol of the service connecting (e.g. tcp) PORT: The port of the service connecting (e.g. 443) SFLAGS: Flags for the the initialization of 's' (if NULL) VFLAGS: Verification flags; an OR'ed list of 'dane_verify_flags_t' . VERIFY: An OR'ed list of 'dane_verify_status_t' . This function will verify the given certificate chain against the CA constrains and/or the certificate available via DANE. If no information via DANE can be obtained the flag 'DANE_VERIFY_NO_DANE_INFO' is set. If a DNSSEC signature is not available for the DANE record then the verify flag 'DANE_VERIFY_NO_DNSSEC_DATA' is set. Note that the CA constraint only applies for the directly certifying CA and does not account for long CA chains. 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. If the 'q' parameter is provided it will be used for caching entries. *Returns:* On success, 'DANE_E_SUCCESS' (0) is returned, otherwise a negative error value. 'INT *note dane_verify_session_crt:: (dane_state_t S, gnutls_session_t SESSION, const char * HOSTNAME, const char * PROTO, unsigned int PORT, unsigned int SFLAGS, unsigned int VFLAGS, unsigned int * VERIFY)' 'CONST CHAR * *note dane_strerror:: (int ERROR)' Note that the 'dane_state_t' structure that is accepted by both verification functions is optional. It is required when many queries are performed to facilitate caching. The following flags are returned by the verify functions to indicate the status of the verification. 'DANE_VERIFY_CA_CONSTRAINTS_VIOLATED' The CA constraints were violated. 'DANE_VERIFY_CERT_DIFFERS' The certificate obtained via DNS differs. 'DANE_VERIFY_UNKNOWN_DANE_INFO' No known DANE data was found in the DNS record. Figure 6.2: The DANE verification status flags. In order to generate a DANE TLSA entry to use in a DNS server you may use danetool (see *note danetool Invocation::).  File: gnutls.info, Node: Parameter generation, Next: Deriving keys for other applications/protocols, Prev: Certificate verification, Up: Advanced topics 6.12.3 Parameter generation --------------------------- Several TLS ciphersuites require additional parameters that need to be generated or provided by the application. The Diffie-Hellman based ciphersuites (ANON-DH or DHE), require the group parameters to be provided. Those can either be be generated on the fly using *note gnutls_dh_params_generate2:: or imported from pregenerated data using *note gnutls_dh_params_import_pkcs3::. The parameters can be used in a TLS session by calling *note gnutls_certificate_set_dh_params:: or *note gnutls_anon_set_server_dh_params:: for anonymous sessions. 'INT *note gnutls_dh_params_generate2:: (gnutls_dh_params_t PARAMS, unsigned int BITS)' 'INT *note gnutls_dh_params_import_pkcs3:: (gnutls_dh_params_t PARAMS, const gnutls_datum_t * PKCS3_PARAMS, gnutls_x509_crt_fmt_t FORMAT)' 'VOID *note gnutls_certificate_set_dh_params:: (gnutls_certificate_credentials_t RES, gnutls_dh_params_t DH_PARAMS)' 'VOID *note gnutls_anon_set_server_dh_params:: (gnutls_anon_server_credentials_t RES, gnutls_dh_params_t DH_PARAMS)' Due to the time-consuming calculations required for the generation of Diffie-Hellman parameters we suggest against performing generation of them within an application. The 'certtool' tool can be used to generate or export known safe values that can be stored in code or in a configuration file to provide the ability to replace. We also recommend the usage of *note gnutls_sec_param_to_pk_bits:: (see *note Selecting cryptographic key sizes::) to determine the bit size of the generated parameters. Note that the information stored in the generated PKCS #3 structure changed with GnuTLS 3.0.9. Since that version the 'privateValueLength' member of the structure is set, allowing the server utilizing the parameters to use keys of the size of the security parameter. This provides better performance in key exchange. To allow renewal of the parameters within an application without accessing the credentials, which are a shared structure, an alternative interface is available using a callback function. -- Function: void gnutls_certificate_set_params_function (gnutls_certificate_credentials_t RES, gnutls_params_function * FUNC) RES: is a gnutls_certificate_credentials_t structure FUNC: is the function to be called This function will set a callback in order for the server to get the Diffie-Hellman or RSA parameters for certificate authentication. The callback should return 'GNUTLS_E_SUCCESS' (0) on success.  File: gnutls.info, Node: Deriving keys for other applications/protocols, Next: Channel Bindings, Prev: Parameter generation, Up: Advanced topics 6.12.4 Deriving keys for other applications/protocols ----------------------------------------------------- In several cases, after a TLS connection is established, it is desirable to derive keys to be used in another application or protocol (e.g., in an other TLS session using pre-shared keys). The following describe GnuTLS' implementation of RFC5705 to extract keys based on a session's master secret. The API to use is *note gnutls_prf::. The function needs to be provided with a label, and additional context data to mix in the 'extra' parameter. Moreover, the API allows to switch the mix of the client and server random nonces, using the 'server_random_first' parameter. In typical uses you don't need it, so a zero value should be provided in 'server_random_first'. For example, after establishing a TLS session using *note gnutls_handshake::, you can obtain 32-bytes to be used as key, using this call: #define MYLABEL "EXPORTER-My-protocol-name" #define MYCONTEXT "my-protocol's-1st-session" char out[32]; rc = gnutls_prf (session, sizeof(MYLABEL)-1, MYLABEL, 0, sizeof(MYCONTEXT)-1, MYCONTEXT, 32, out); The output key depends on TLS' master secret, and is the same on both client and server. If you don't want to use the RFC5705 interface and not mix in the client and server random nonces, there is a low-level TLS PRF interface called *note gnutls_prf_raw::.  File: gnutls.info, Node: Channel Bindings, Next: Interoperability, Prev: Deriving keys for other applications/protocols, Up: Advanced topics 6.12.5 Channel bindings ----------------------- In user authentication protocols (e.g., EAP or SASL mechanisms) it is useful to have a unique string that identifies the secure channel that is used, to bind together the user authentication with the secure channel. This can protect against man-in-the-middle attacks in some situations. That unique string is called a "channel binding". For background and discussion see [_RFC5056_]. In GnuTLS you can extract a channel binding using the *note gnutls_session_channel_binding:: function. Currently only the type 'GNUTLS_CB_TLS_UNIQUE' is supported, which corresponds to the 'tls-unique' channel binding for TLS defined in [_RFC5929_]. The following example describes how to print the channel binding data. Note that it must be run after a successful TLS handshake. { gnutls_datum_t cb; int rc; rc = gnutls_session_channel_binding (session, GNUTLS_CB_TLS_UNIQUE, &cb); if (rc) fprintf (stderr, "Channel binding error: %s\n", gnutls_strerror (rc)); else { size_t i; printf ("- Channel binding 'tls-unique': "); for (i = 0; i < cb.size; i++) printf ("%02x", cb.data[i]); printf ("\n"); } }  File: gnutls.info, Node: Interoperability, Next: Compatibility with the OpenSSL library, Prev: Channel Bindings, Up: Advanced topics 6.12.6 Interoperability ----------------------- The TLS protocols support many ciphersuites, extensions and version numbers. As a result, few implementations are not able to properly interoperate once faced with extensions or version protocols they do not support and understand. The TLS protocol allows for a graceful downgrade to the commonly supported options, but practice shows it is not always implemented correctly. Because there is no way to achieve maximum interoperability with broken peers without sacrificing security, GnuTLS ignores such peers by default. This might not be acceptable in cases where maximum compatibility is required. Thus we allow enabling compatibility with broken peers using priority strings (see *note Priority Strings::). A conservative priority string that would disable certain TLS protocol options that are known to cause compatibility problems, is shown below. NORMAL:%COMPAT For broken peers that do not tolerate TLS version numbers over TLS 1.0 another priority string is: NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0:+VERS-SSL3.0:%COMPAT This priority string will in addition to above, only enable SSL 3.0 and TLS 1.0 as protocols.  File: gnutls.info, Node: Compatibility with the OpenSSL library, Prev: Interoperability, Up: Advanced topics 6.12.7 Compatibility with the OpenSSL library --------------------------------------------- To ease GnuTLS' integration with existing applications, a compatibility layer with the OpenSSL library is included in the 'gnutls-openssl' library. This compatibility layer is not complete and it is not intended to completely re-implement the OpenSSL API with GnuTLS. It only provides limited source-level compatibility. The prototypes for the compatibility functions are in the 'gnutls/openssl.h' header file. The limitations imposed by the compatibility layer include: * Error handling is not thread safe.  File: gnutls.info, Node: GnuTLS application examples, Next: Using GnuTLS as a cryptographic library, Prev: How to use GnuTLS in applications, Up: Top 7 GnuTLS application examples ***************************** In this chapter several examples of real-world use cases are listed. The examples are simplified to promote readability and contain little or no error checking. * Menu: * Client examples:: * Server examples:: * OCSP example:: * Miscellaneous examples:: * XSSL examples::  File: gnutls.info, Node: Client examples, Next: Server examples, Up: GnuTLS application examples 7.1 Client examples =================== This section contains examples of TLS and SSL clients, using GnuTLS. Note that some of the examples require functions implemented by another example. * Menu: * Simple client example with X.509 certificate support:: * Simple client example with SSH-style certificate verification:: * Simple client example with anonymous authentication:: * Simple Datagram TLS client example:: * Obtaining session information:: * Using a callback to select the certificate to use:: * Verifying a certificate:: * Client using a smart card with TLS:: * Client with Resume capability example:: * Simple client example with SRP authentication:: * Simple client example in C++:: * Helper functions for TCP connections:: * Helper functions for UDP connections::  File: gnutls.info, Node: Simple client example with X.509 certificate support, Next: Simple client example with SSH-style certificate verification, Up: Client examples 7.1.1 Simple client example with X.509 certificate support ---------------------------------------------------------- Let's assume now that we want to create a TCP client which communicates with servers that use X.509 or OpenPGP certificate authentication. The following client is a very simple TLS client, which uses the high level verification functions for certificates, but does not support session resumption. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "examples.h" /* A very basic TLS client, with X.509 authentication and server certificate * verification. Note that error checking for missing files etc. is omitted * for simplicity. */ #define MAX_BUF 1024 #define CAFILE "/etc/ssl/certs/ca-certificates.crt" #define MSG "GET / HTTP/1.0\r\n\r\n" extern int tcp_connect(void); extern void tcp_close(int sd); static int _verify_certificate_callback(gnutls_session_t session); int main(void) { int ret, sd, ii; gnutls_session_t session; char buffer[MAX_BUF + 1]; const char *err; gnutls_certificate_credentials_t xcred; gnutls_global_init(); /* X509 stuff */ gnutls_certificate_allocate_credentials(&xcred); /* sets the trusted cas file */ gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_verify_function(xcred, _verify_certificate_callback); /* If client holds a certificate it can be set using the following: * gnutls_certificate_set_x509_key_file (xcred, "cert.pem", "key.pem", GNUTLS_X509_FMT_PEM); */ /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT); gnutls_session_set_ptr(session, (void *) "my_host_name"); gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name", strlen("my_host_name")); /* use default priorities */ gnutls_set_default_priority(session); #if 0 /* if more fine-graned control is required */ ret = gnutls_priority_set_direct(session, "NORMAL", &err); if (ret < 0) { if (ret == GNUTLS_E_INVALID_REQUEST) { fprintf(stderr, "Syntax error at: %s\n", err); } exit(1); } #endif /* put the x509 credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); /* connect to the peer */ sd = tcp_connect(); gnutls_transport_set_int(session, sd); gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } if (ret > 0) { printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); } gnutls_bye(session, GNUTLS_SHUT_RDWR); end: tcp_close(sd); gnutls_deinit(session); gnutls_certificate_free_credentials(xcred); gnutls_global_deinit(); return 0; } /* This function will verify the peer's certificate, and check * if the hostname matches, as well as the activation, expiration dates. */ static int _verify_certificate_callback(gnutls_session_t session) { unsigned int status; int ret, type; const char *hostname; gnutls_datum_t out; /* read hostname */ hostname = gnutls_session_get_ptr(session); /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers3(session, hostname, &status); if (ret < 0) { printf("Error\n"); return GNUTLS_E_CERTIFICATE_ERROR; } type = gnutls_certificate_type_get(session); ret = gnutls_certificate_verification_status_print(status, type, &out, 0); if (ret < 0) { printf("Error\n"); return GNUTLS_E_CERTIFICATE_ERROR; } printf("%s", out.data); gnutls_free(out.data); if (status != 0) /* Certificate is not trusted */ return GNUTLS_E_CERTIFICATE_ERROR; /* notify gnutls to continue handshake normally */ return 0; }  File: gnutls.info, Node: Simple client example with SSH-style certificate verification, Next: Simple client example with anonymous authentication, Prev: Simple client example with X.509 certificate support, Up: Client examples 7.1.2 Simple client example with SSH-style certificate verification ------------------------------------------------------------------- This is an alternative verification function that will use the X.509 certificate authorities for verification, but also assume an trust on first use (SSH-like) authentication system. That is the user is prompted on unknown public keys and known public keys are considered trusted. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "examples.h" /* This function will verify the peer's certificate, check * if the hostname matches. In addition it will perform an * SSH-style authentication, where ultimately trusted keys * are only the keys that have been seen before. */ int _ssh_verify_certificate_callback(gnutls_session_t session) { unsigned int status; const gnutls_datum_t *cert_list; unsigned int cert_list_size; int ret, type; gnutls_datum_t out; const char *hostname; /* read hostname */ hostname = gnutls_session_get_ptr(session); /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers3(session, hostname, &status); if (ret < 0) { printf("Error\n"); return GNUTLS_E_CERTIFICATE_ERROR; } type = gnutls_certificate_type_get(session); ret = gnutls_certificate_verification_status_print(status, type, &out, 0); if (ret < 0) { printf("Error\n"); return GNUTLS_E_CERTIFICATE_ERROR; } printf("%s", out.data); gnutls_free(out.data); if (status != 0) /* Certificate is not trusted */ return GNUTLS_E_CERTIFICATE_ERROR; /* Do SSH verification */ cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (cert_list == NULL) { printf("No certificate was found!\n"); return GNUTLS_E_CERTIFICATE_ERROR; } /* service may be obtained alternatively using getservbyport() */ ret = gnutls_verify_stored_pubkey(NULL, NULL, hostname, "https", type, &cert_list[0], 0); if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) { printf("Host %s is not known.", hostname); if (status == 0) printf("Its certificate is valid for %s.\n", hostname); /* the certificate must be printed and user must be asked on * whether it is trustworthy. --see gnutls_x509_crt_print() */ /* if not trusted */ return GNUTLS_E_CERTIFICATE_ERROR; } else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) { printf ("Warning: host %s is known but has another key associated.", hostname); printf ("It might be that the server has multiple keys, or you are under attack\n"); if (status == 0) printf("Its certificate is valid for %s.\n", hostname); /* the certificate must be printed and user must be asked on * whether it is trustworthy. --see gnutls_x509_crt_print() */ /* if not trusted */ return GNUTLS_E_CERTIFICATE_ERROR; } else if (ret < 0) { printf("gnutls_verify_stored_pubkey: %s\n", gnutls_strerror(ret)); return ret; } /* user trusts the key -> store it */ if (ret != 0) { ret = gnutls_store_pubkey(NULL, NULL, hostname, "https", type, &cert_list[0], 0, 0); if (ret < 0) printf("gnutls_store_pubkey: %s\n", gnutls_strerror(ret)); } /* notify gnutls to continue handshake normally */ return 0; }  File: gnutls.info, Node: Simple client example with anonymous authentication, Next: Simple Datagram TLS client example, Prev: Simple client example with SSH-style certificate verification, Up: Client examples 7.1.3 Simple client example with anonymous authentication --------------------------------------------------------- The simplest client using TLS is the one that doesn't do any authentication. This means no external certificates or passwords are needed to set up the connection. As could be expected, the connection is vulnerable to man-in-the-middle (active or redirection) attacks. However, the data are integrity protected and encrypted from passive eavesdroppers. Note that due to the vulnerable nature of this method very few public servers support it. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include /* A very basic TLS client, with anonymous authentication. */ #define MAX_BUF 1024 #define MSG "GET / HTTP/1.0\r\n\r\n" extern int tcp_connect(void); extern void tcp_close(int sd); int main(void) { int ret, sd, ii; gnutls_session_t session; char buffer[MAX_BUF + 1]; gnutls_anon_client_credentials_t anoncred; /* Need to enable anonymous KX specifically. */ gnutls_global_init(); gnutls_anon_allocate_client_credentials(&anoncred); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT); /* Use default priorities */ gnutls_priority_set_direct(session, "PERFORMANCE:+ANON-ECDH:+ANON-DH", NULL); /* put the anonymous credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); /* connect to the peer */ sd = tcp_connect(); gnutls_transport_set_int(session, sd); gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } if (ret > 0) { printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); } gnutls_bye(session, GNUTLS_SHUT_RDWR); end: tcp_close(sd); gnutls_deinit(session); gnutls_anon_free_client_credentials(anoncred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Simple Datagram TLS client example, Next: Obtaining session information, Prev: Simple client example with anonymous authentication, Up: Client examples 7.1.4 Simple datagram TLS client example ---------------------------------------- This is a client that uses UDP to connect to a server. This is the DTLS equivalent to the TLS example with X.509 certificates. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include /* A very basic Datagram TLS client, over UDP with X.509 authentication. */ #define MAX_BUF 1024 #define CAFILE "/etc/ssl/certs/ca-certificates.crt" #define MSG "GET / HTTP/1.0\r\n\r\n" extern int udp_connect(void); extern void udp_close(int sd); extern int verify_certificate_callback(gnutls_session_t session); int main(void) { int ret, sd, ii; gnutls_session_t session; char buffer[MAX_BUF + 1]; const char *err; gnutls_certificate_credentials_t xcred; gnutls_global_init(); /* X509 stuff */ gnutls_certificate_allocate_credentials(&xcred); /* sets the trusted cas file */ gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_verify_function(xcred, verify_certificate_callback); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM); /* Use default priorities */ ret = gnutls_priority_set_direct(session, "NORMAL", &err); if (ret < 0) { if (ret == GNUTLS_E_INVALID_REQUEST) { fprintf(stderr, "Syntax error at: %s\n", err); } exit(1); } /* put the x509 credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name", strlen("my_host_name")); /* connect to the peer */ sd = udp_connect(); gnutls_transport_set_int(session, sd); /* set the connection MTU */ gnutls_dtls_set_mtu(session, 1000); gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET */ if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } if (ret > 0) { printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); } /* It is suggested not to use GNUTLS_SHUT_RDWR in DTLS * connections because the peer's closure message might * be lost */ gnutls_bye(session, GNUTLS_SHUT_WR); end: udp_close(sd); gnutls_deinit(session); gnutls_certificate_free_credentials(xcred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Obtaining session information, Next: Using a callback to select the certificate to use, Prev: Simple Datagram TLS client example, Up: Client examples 7.1.5 Obtaining session information ----------------------------------- Most of the times it is desirable to know the security properties of the current established session. This includes the underlying ciphers and the protocols involved. That is the purpose of the following function. Note that this function will print meaningful values only if called after a successful *note gnutls_handshake::. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "examples.h" /* This function will print some details of the * given session. */ int print_info(gnutls_session_t session) { const char *tmp; gnutls_credentials_type_t cred; gnutls_kx_algorithm_t kx; int dhe, ecdh; dhe = ecdh = 0; /* print the key exchange's algorithm name */ kx = gnutls_kx_get(session); tmp = gnutls_kx_get_name(kx); printf("- Key Exchange: %s\n", tmp); /* Check the authentication type used and switch * to the appropriate. */ cred = gnutls_auth_get_type(session); switch (cred) { case GNUTLS_CRD_IA: printf("- TLS/IA session\n"); break; #ifdef ENABLE_SRP case GNUTLS_CRD_SRP: printf("- SRP session with username %s\n", gnutls_srp_server_get_username(session)); break; #endif case GNUTLS_CRD_PSK: /* This returns NULL in server side. */ if (gnutls_psk_client_get_hint(session) != NULL) printf("- PSK authentication. PSK hint '%s'\n", gnutls_psk_client_get_hint(session)); /* This returns NULL in client side. */ if (gnutls_psk_server_get_username(session) != NULL) printf("- PSK authentication. Connected as '%s'\n", gnutls_psk_server_get_username(session)); if (kx == GNUTLS_KX_ECDHE_PSK) ecdh = 1; else if (kx == GNUTLS_KX_DHE_PSK) dhe = 1; break; case GNUTLS_CRD_ANON: /* anonymous authentication */ printf("- Anonymous authentication.\n"); if (kx == GNUTLS_KX_ANON_ECDH) ecdh = 1; else if (kx == GNUTLS_KX_ANON_DH) dhe = 1; break; case GNUTLS_CRD_CERTIFICATE: /* certificate authentication */ /* Check if we have been using ephemeral Diffie-Hellman. */ if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) dhe = 1; else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) ecdh = 1; /* if the certificate list is available, then * print some information about it. */ print_x509_certificate_info(session); } /* switch */ if (ecdh != 0) printf("- Ephemeral ECDH using curve %s\n", gnutls_ecc_curve_get_name(gnutls_ecc_curve_get (session))); else if (dhe != 0) printf("- Ephemeral DH using prime of %d bits\n", gnutls_dh_get_prime_bits(session)); /* print the protocol's name (ie TLS 1.0) */ tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(session)); printf("- Protocol: %s\n", tmp); /* print the certificate type of the peer. * ie X.509 */ tmp = gnutls_certificate_type_get_name(gnutls_certificate_type_get (session)); printf("- Certificate Type: %s\n", tmp); /* print the compression algorithm (if any) */ tmp = gnutls_compression_get_name(gnutls_compression_get(session)); printf("- Compression: %s\n", tmp); /* print the name of the cipher used. * ie 3DES. */ tmp = gnutls_cipher_get_name(gnutls_cipher_get(session)); printf("- Cipher: %s\n", tmp); /* Print the MAC algorithms name. * ie SHA1 */ tmp = gnutls_mac_get_name(gnutls_mac_get(session)); printf("- MAC: %s\n", tmp); return 0; }  File: gnutls.info, Node: Using a callback to select the certificate to use, Next: Verifying a certificate, Prev: Obtaining session information, Up: Client examples 7.1.6 Using a callback to select the certificate to use ------------------------------------------------------- There are cases where a client holds several certificate and key pairs, and may not want to load all of them in the credentials structure. The following example demonstrates the use of the certificate selection callback. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include /* A TLS client that loads the certificate and key. */ #define MAX_BUF 1024 #define MSG "GET / HTTP/1.0\r\n\r\n" #define CERT_FILE "cert.pem" #define KEY_FILE "key.pem" #define CAFILE "/etc/ssl/certs/ca-certificates.crt" extern int tcp_connect(void); extern void tcp_close(int sd); static int cert_callback(gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_pcert_st ** pcert, unsigned int *pcert_length, gnutls_privkey_t * pkey); gnutls_pcert_st pcrt; gnutls_privkey_t key; /* Load the certificate and the private key. */ static void load_keys(void) { int ret; gnutls_datum_t data; ret = gnutls_load_file(CERT_FILE, &data); if (ret < 0) { fprintf(stderr, "*** Error loading certificate file.\n"); exit(1); } ret = gnutls_pcert_import_x509_raw(&pcrt, &data, GNUTLS_X509_FMT_PEM, 0); if (ret < 0) { fprintf(stderr, "*** Error loading certificate file: %s\n", gnutls_strerror(ret)); exit(1); } gnutls_free(data.data); ret = gnutls_load_file(KEY_FILE, &data); if (ret < 0) { fprintf(stderr, "*** Error loading key file.\n"); exit(1); } gnutls_privkey_init(&key); ret = gnutls_privkey_import_x509_raw(key, &data, GNUTLS_X509_FMT_PEM, NULL, 0); if (ret < 0) { fprintf(stderr, "*** Error loading key file: %s\n", gnutls_strerror(ret)); exit(1); } gnutls_free(data.data); } int main(void) { int ret, sd, ii; gnutls_session_t session; gnutls_priority_t priorities_cache; char buffer[MAX_BUF + 1]; gnutls_certificate_credentials_t xcred; /* Allow connections to servers that have OpenPGP keys as well. */ gnutls_global_init(); load_keys(); /* X509 stuff */ gnutls_certificate_allocate_credentials(&xcred); /* priorities */ gnutls_priority_init(&priorities_cache, "NORMAL", NULL); /* sets the trusted cas file */ gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_retrieve_function2(xcred, cert_callback); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT); /* Use default priorities */ gnutls_priority_set(session, priorities_cache); /* put the x509 credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); /* connect to the peer */ sd = tcp_connect(); gnutls_transport_set_int(session, sd); /* Perform the TLS handshake */ ret = gnutls_handshake(session); if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); gnutls_bye(session, GNUTLS_SHUT_RDWR); end: tcp_close(sd); gnutls_deinit(session); gnutls_certificate_free_credentials(xcred); gnutls_priority_deinit(priorities_cache); gnutls_global_deinit(); return 0; } /* This callback should be associated with a session by calling * gnutls_certificate_client_set_retrieve_function( session, cert_callback), * before a handshake. */ static int cert_callback(gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_pcert_st ** pcert, unsigned int *pcert_length, gnutls_privkey_t * pkey) { char issuer_dn[256]; int i, ret; size_t len; gnutls_certificate_type_t type; /* Print the server's trusted CAs */ if (nreqs > 0) printf("- Server's trusted authorities:\n"); else printf ("- Server did not send us any trusted authorities names.\n"); /* print the names (if any) */ for (i = 0; i < nreqs; i++) { len = sizeof(issuer_dn); ret = gnutls_x509_rdn_get(&req_ca_rdn[i], issuer_dn, &len); if (ret >= 0) { printf(" [%d]: ", i); printf("%s\n", issuer_dn); } } /* Select a certificate and return it. * The certificate must be of any of the "sign algorithms" * supported by the server. */ type = gnutls_certificate_type_get(session); if (type == GNUTLS_CRT_X509) { *pcert_length = 1; *pcert = &pcrt; *pkey = key; } else { return -1; } return 0; }  File: gnutls.info, Node: Verifying a certificate, Next: Client using a smart card with TLS, Prev: Using a callback to select the certificate to use, Up: Client examples 7.1.7 Verifying a certificate ----------------------------- An example is listed below which uses the high level verification functions to verify a given certificate list. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "examples.h" /* All the available CRLs */ gnutls_x509_crl_t *crl_list; int crl_list_size; /* All the available trusted CAs */ gnutls_x509_crt_t *ca_list; int ca_list_size; static int print_details_func(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl, unsigned int verification_output); /* This function will try to verify the peer's certificate chain, and * also check if the hostname matches. */ void verify_certificate_chain(const char *hostname, const gnutls_datum_t * cert_chain, int cert_chain_length) { int i; gnutls_x509_trust_list_t tlist; gnutls_x509_crt_t *cert; unsigned int output; /* Initialize the trusted certificate list. This should be done * once on initialization. gnutls_x509_crt_list_import2() and * gnutls_x509_crl_list_import2() can be used to load them. */ gnutls_x509_trust_list_init(&tlist, 0); gnutls_x509_trust_list_add_cas(tlist, ca_list, ca_list_size, 0); gnutls_x509_trust_list_add_crls(tlist, crl_list, crl_list_size, GNUTLS_TL_VERIFY_CRL, 0); cert = malloc(sizeof(*cert) * cert_chain_length); /* Import all the certificates in the chain to * native certificate format. */ for (i = 0; i < cert_chain_length; i++) { gnutls_x509_crt_init(&cert[i]); gnutls_x509_crt_import(cert[i], &cert_chain[i], GNUTLS_X509_FMT_DER); } gnutls_x509_trust_list_verify_named_crt(tlist, cert[0], hostname, strlen(hostname), GNUTLS_VERIFY_DISABLE_CRL_CHECKS, &output, print_details_func); /* if this certificate is not explicitly trusted verify against CAs */ if (output != 0) { gnutls_x509_trust_list_verify_crt(tlist, cert, cert_chain_length, 0, &output, print_details_func); } if (output & GNUTLS_CERT_INVALID) { fprintf(stderr, "Not trusted"); if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) fprintf(stderr, ": no issuer was found"); if (output & GNUTLS_CERT_SIGNER_NOT_CA) fprintf(stderr, ": issuer is not a CA"); if (output & GNUTLS_CERT_NOT_ACTIVATED) fprintf(stderr, ": not yet activated\n"); if (output & GNUTLS_CERT_EXPIRED) fprintf(stderr, ": expired\n"); fprintf(stderr, "\n"); } else fprintf(stderr, "Trusted\n"); /* Check if the name in the first certificate matches our destination! */ if (!gnutls_x509_crt_check_hostname(cert[0], hostname)) { printf ("The certificate's owner does not match hostname '%s'\n", hostname); } gnutls_x509_trust_list_deinit(tlist, 1); return; } static int print_details_func(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl, unsigned int verification_output) { char name[512]; char issuer_name[512]; size_t name_size; size_t issuer_name_size; issuer_name_size = sizeof(issuer_name); gnutls_x509_crt_get_issuer_dn(cert, issuer_name, &issuer_name_size); name_size = sizeof(name); gnutls_x509_crt_get_dn(cert, name, &name_size); fprintf(stdout, "\tSubject: %s\n", name); fprintf(stdout, "\tIssuer: %s\n", issuer_name); if (issuer != NULL) { issuer_name_size = sizeof(issuer_name); gnutls_x509_crt_get_dn(issuer, issuer_name, &issuer_name_size); fprintf(stdout, "\tVerified against: %s\n", issuer_name); } if (crl != NULL) { issuer_name_size = sizeof(issuer_name); gnutls_x509_crl_get_issuer_dn(crl, issuer_name, &issuer_name_size); fprintf(stdout, "\tVerified against CRL of: %s\n", issuer_name); } fprintf(stdout, "\tVerification output: %x\n\n", verification_output); return 0; }  File: gnutls.info, Node: Client using a smart card with TLS, Next: Client with Resume capability example, Prev: Verifying a certificate, Up: Client examples 7.1.8 Using a smart card with TLS --------------------------------- This example will demonstrate how to load keys and certificates from a smart-card or any other PKCS #11 token, and use it in a TLS connection. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for getpass() */ /* A TLS client that loads the certificate and key. */ #define MAX_BUF 1024 #define MSG "GET / HTTP/1.0\r\n\r\n" #define MIN(x,y) (((x)<(y))?(x):(y)) #define CAFILE "/etc/ssl/certs/ca-certificates.crt" /* The URLs of the objects can be obtained * using p11tool --list-all --login */ #define KEY_URL "pkcs11:manufacturer=SomeManufacturer;object=Private%20Key" \ ";objecttype=private;id=%db%5b%3e%b5%72%33" #define CERT_URL "pkcs11:manufacturer=SomeManufacturer;object=Certificate;" \ "objecttype=cert;id=db%5b%3e%b5%72%33" extern int tcp_connect(void); extern void tcp_close(int sd); static int pin_callback(void *user, int attempt, const char *token_url, const char *token_label, unsigned int flags, char *pin, size_t pin_max) { const char *password; int len; printf("PIN required for token '%s' with URL '%s'\n", token_label, token_url); if (flags & GNUTLS_PIN_FINAL_TRY) printf("*** This is the final try before locking!\n"); if (flags & GNUTLS_PIN_COUNT_LOW) printf("*** Only few tries left before locking!\n"); if (flags & GNUTLS_PIN_WRONG) printf("*** Wrong PIN\n"); password = getpass("Enter pin: "); if (password == NULL || password[0] == 0) { fprintf(stderr, "No password given\n"); exit(1); } len = MIN(pin_max - 1, strlen(password)); memcpy(pin, password, len); pin[len] = 0; return 0; } int main(void) { int ret, sd, ii; gnutls_session_t session; gnutls_priority_t priorities_cache; char buffer[MAX_BUF + 1]; gnutls_certificate_credentials_t xcred; /* Allow connections to servers that have OpenPGP keys as well. */ gnutls_global_init(); /* PKCS11 private key operations might require PIN. * Register a callback. */ gnutls_pkcs11_set_pin_function(pin_callback, NULL); /* X509 stuff */ gnutls_certificate_allocate_credentials(&xcred); /* priorities */ gnutls_priority_init(&priorities_cache, "NORMAL", NULL); /* sets the trusted cas file */ gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_key_file(xcred, CERT_URL, KEY_URL, GNUTLS_X509_FMT_DER); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT); /* Use default priorities */ gnutls_priority_set(session, priorities_cache); /* put the x509 credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); /* connect to the peer */ sd = tcp_connect(); gnutls_transport_set_int(session, sd); /* Perform the TLS handshake */ ret = gnutls_handshake(session); if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); gnutls_bye(session, GNUTLS_SHUT_RDWR); end: tcp_close(sd); gnutls_deinit(session); gnutls_certificate_free_credentials(xcred); gnutls_priority_deinit(priorities_cache); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Client with Resume capability example, Next: Simple client example with SRP authentication, Prev: Client using a smart card with TLS, Up: Client examples 7.1.9 Client with resume capability example ------------------------------------------- This is a modification of the simple client example. Here we demonstrate the use of session resumption. The client tries to connect once using TLS, close the connection and then try to establish a new connection using the previously negotiated data. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include /* Those functions are defined in other examples. */ extern void check_alert(gnutls_session_t session, int ret); extern int tcp_connect(void); extern void tcp_close(int sd); #define MAX_BUF 1024 #define CAFILE "/etc/ssl/certs/ca-certificates.crt" #define MSG "GET / HTTP/1.0\r\n\r\n" int main(void) { int ret; int sd, ii; gnutls_session_t session; char buffer[MAX_BUF + 1]; gnutls_certificate_credentials_t xcred; /* variables used in session resuming */ int t; char *session_data = NULL; size_t session_data_size = 0; gnutls_global_init(); /* X509 stuff */ gnutls_certificate_allocate_credentials(&xcred); gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); for (t = 0; t < 2; t++) { /* connect 2 times to the server */ sd = tcp_connect(); gnutls_init(&session, GNUTLS_CLIENT); gnutls_priority_set_direct(session, "PERFORMANCE:!ARCFOUR-128", NULL); gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); if (t > 0) { /* if this is not the first time we connect */ gnutls_session_set_data(session, session_data, session_data_size); free(session_data); } gnutls_transport_set_int(session, sd); gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { printf("- Handshake was completed\n"); } if (t == 0) { /* the first time we connect */ /* get the session data size */ gnutls_session_get_data(session, NULL, &session_data_size); session_data = malloc(session_data_size); /* put session data to the session variable */ gnutls_session_get_data(session, session_data, &session_data_size); } else { /* the second time we connect */ /* check if we actually resumed the previous session */ if (gnutls_session_is_resumed(session) != 0) { printf("- Previous session was resumed\n"); } else { fprintf(stderr, "*** Previous session was NOT resumed\n"); } } /* This function was defined in a previous example */ /* print_info(session); */ gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } if (ret > 0) { printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); } gnutls_bye(session, GNUTLS_SHUT_RDWR); end: tcp_close(sd); gnutls_deinit(session); } /* for() */ gnutls_certificate_free_credentials(xcred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Simple client example with SRP authentication, Next: Simple client example in C++, Prev: Client with Resume capability example, Up: Client examples 7.1.10 Simple client example with SRP authentication ---------------------------------------------------- The following client is a very simple SRP TLS client which connects to a server and authenticates using a _username_ and a _password_. The server may authenticate itself using a certificate, and in that case it has to be verified. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include /* 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; gnutls_global_init(); gnutls_srp_allocate_client_credentials(&srp_cred); gnutls_certificate_allocate_credentials(&cert_cred); gnutls_certificate_set_x509_trust_file(cert_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_srp_set_client_credentials(srp_cred, USERNAME, PASSWORD); /* connects to server */ sd = tcp_connect(); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT); /* Set the priorities. */ gnutls_priority_set_direct(session, "NORMAL:+SRP:+SRP-RSA:+SRP-DSS", NULL); /* put the SRP credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred); gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); gnutls_transport_set_int(session, sd); gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); goto end; } else { char *desc; desc = gnutls_session_get_desc(session); printf("- Session info: %s\n", desc); gnutls_free(desc); } gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); if (gnutls_error_is_fatal(ret) != 0 || ret == 0) { if (ret == 0) { printf ("- Peer has closed the GnuTLS connection\n"); goto end; } else { fprintf(stderr, "*** Error: %s\n", gnutls_strerror(ret)); goto end; } } else check_alert(session, ret); if (ret > 0) { printf("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc(buffer[ii], stdout); } fputs("\n", stdout); } gnutls_bye(session, GNUTLS_SHUT_RDWR); end: tcp_close(sd); gnutls_deinit(session); gnutls_srp_free_client_credentials(srp_cred); gnutls_certificate_free_credentials(cert_cred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Simple client example in C++, Next: Helper functions for TCP connections, Prev: Simple client example with SRP authentication, Up: Client examples 7.1.11 Simple client example using the C++ API ---------------------------------------------- The following client is a simple example of a client client utilizing the GnuTLS C++ API. #include #include #include #include #include #include /* for strlen */ /* A very basic TLS client, with anonymous authentication. * written by Eduardo Villanueva Che. */ #define MAX_BUF 1024 #define SA struct sockaddr #define CAFILE "ca.pem" #define MSG "GET / HTTP/1.0\r\n\r\n" extern "C" { int tcp_connect(void); void tcp_close(int sd); } int main(void) { int sd = -1; gnutls_global_init(); try { /* Allow connections to servers that have OpenPGP keys as well. */ gnutls::client_session session; /* X509 stuff */ gnutls::certificate_credentials credentials; /* sets the trusted cas file */ credentials.set_x509_trust_file(CAFILE, GNUTLS_X509_FMT_PEM); /* put the x509 credentials to the current session */ session.set_credentials(credentials); /* Use default priorities */ session.set_priority ("NORMAL", NULL); /* connect to the peer */ sd = tcp_connect(); session.set_transport_ptr((gnutls_transport_ptr_t) (ptrdiff_t)sd); /* Perform the TLS handshake */ int ret = session.handshake(); if (ret < 0) { throw std::runtime_error("Handshake failed"); } else { std::cout << "- Handshake was completed" << std::endl; } session.send(MSG, strlen(MSG)); char buffer[MAX_BUF + 1]; ret = session.recv(buffer, MAX_BUF); if (ret == 0) { throw std::runtime_error("Peer has closed the TLS connection"); } else if (ret < 0) { throw std::runtime_error(gnutls_strerror(ret)); } std::cout << "- Received " << ret << " bytes:" << std::endl; std::cout.write(buffer, ret); std::cout << std::endl; session.bye(GNUTLS_SHUT_RDWR); } catch (std::exception &ex) { std::cerr << "Exception caught: " << ex.what() << std::endl; } if (sd != -1) tcp_close(sd); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Helper functions for TCP connections, Next: Helper functions for UDP connections, Prev: Simple client example in C++, Up: Client examples 7.1.12 Helper functions for TCP connections ------------------------------------------- Those helper function abstract away TCP connection handling from the other examples. It is required to build some examples. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include /* tcp.c */ int tcp_connect(void); void tcp_close(int sd); /* Connects to the peer and returns a socket * descriptor. */ extern int tcp_connect(void) { const char *PORT = "5556"; const char *SERVER = "127.0.0.1"; int err, sd; struct sockaddr_in sa; /* connects to server */ sd = socket(AF_INET, SOCK_STREAM, 0); memset(&sa, '\0', sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(atoi(PORT)); inet_pton(AF_INET, SERVER, &sa.sin_addr); err = connect(sd, (struct sockaddr *) &sa, sizeof(sa)); if (err < 0) { fprintf(stderr, "Connect error\n"); exit(1); } return sd; } /* closes the given socket descriptor. */ extern void tcp_close(int sd) { shutdown(sd, SHUT_RDWR); /* no more receptions */ close(sd); }  File: gnutls.info, Node: Helper functions for UDP connections, Prev: Helper functions for TCP connections, Up: Client examples 7.1.13 Helper functions for UDP connections ------------------------------------------- The UDP helper functions abstract away UDP connection handling from the other examples. It is required to build the examples using UDP. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include /* udp.c */ int udp_connect(void); void udp_close(int sd); /* Connects to the peer and returns a socket * descriptor. */ extern int udp_connect(void) { const char *PORT = "5557"; const char *SERVER = "127.0.0.1"; int err, sd, optval; struct sockaddr_in sa; /* connects to server */ sd = socket(AF_INET, SOCK_DGRAM, 0); memset(&sa, '\0', sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(atoi(PORT)); inet_pton(AF_INET, SERVER, &sa.sin_addr); #if defined(IP_DONTFRAG) optval = 1; setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &optval, sizeof(optval)); #elif defined(IP_MTU_DISCOVER) optval = IP_PMTUDISC_DO; setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void *) &optval, sizeof(optval)); #endif err = connect(sd, (struct sockaddr *) &sa, sizeof(sa)); if (err < 0) { fprintf(stderr, "Connect error\n"); exit(1); } return sd; } /* closes the given socket descriptor. */ extern void udp_close(int sd) { close(sd); }  File: gnutls.info, Node: Server examples, Next: OCSP example, Prev: Client examples, Up: GnuTLS application examples 7.2 Server examples =================== This section contains examples of TLS and SSL servers, using GnuTLS. * Menu: * Echo server with X.509 authentication:: * Echo server with OpenPGP authentication:: * Echo server with SRP authentication:: * Echo server with anonymous authentication:: * DTLS echo server with X.509 authentication::  File: gnutls.info, Node: Echo server with X.509 authentication, Next: Echo server with OpenPGP authentication, Up: Server examples 7.2.1 Echo server with X.509 authentication ------------------------------------------- This example is a very simple echo server which supports X.509 authentication. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #define KEYFILE "key.pem" #define CERTFILE "cert.pem" #define CAFILE "/etc/ssl/certs/ca-certificates.crt" #define CRLFILE "crl.pem" /* The OCSP status file contains up to date information about revocation * of the server's certificate. That can be periodically be updated * using: * $ ocsptool --ask --load-cert your_cert.pem --load-issuer your_issuer.pem * --load-signer your_issuer.pem --outfile ocsp-status.der */ #define OCSP_STATUS_FILE "ocsp-status.der" /* This is a sample TLS 1.0 echo server, using X.509 authentication and * OCSP stapling support. */ #define MAX_BUF 1024 #define PORT 5556 /* listen to 5556 port */ /* These are global */ static gnutls_dh_params_t dh_params; static int generate_dh_params(void) { unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); /* Generate Diffie-Hellman parameters - for use with DHE * kx algorithms. When short bit length is used, it might * be wise to regenerate parameters often. */ gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, bits); return 0; } int main(void) { int listen_sd; int sd, ret; gnutls_certificate_credentials_t x509_cred; gnutls_priority_t priority_cache; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; socklen_t client_len; char topbuf[512]; gnutls_session_t session; char buffer[MAX_BUF + 1]; int optval = 1; /* this must be called once in the program */ gnutls_global_init(); gnutls_certificate_allocate_credentials(&x509_cred); /* gnutls_certificate_set_x509_system_trust(xcred); */ gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM); ret = gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM); if (ret < 0) { printf("No certificate or key were found\n"); exit(1); } /* loads an OCSP status request if available */ gnutls_certificate_set_ocsp_status_request_file(x509_cred, OCSP_STATUS_FILE, 0); generate_dh_params(); gnutls_priority_init(&priority_cache, "PERFORMANCE:%SERVER_PRECEDENCE", NULL); gnutls_certificate_set_dh_params(x509_cred, dh_params); /* Socket operations */ listen_sd = socket(AF_INET, SOCK_STREAM, 0); memset(&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons(PORT); /* Server Port number */ setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof(int)); bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); listen(listen_sd, 1024); printf("Server ready. Listening to port '%d'.\n\n", PORT); client_len = sizeof(sa_cli); for (;;) { gnutls_init(&session, GNUTLS_SERVER); gnutls_priority_set(session, priority_cache); gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); /* We don't request any certificate from the client. * If we did we would need to verify it. */ gnutls_certificate_server_set_request(session, GNUTLS_CERT_IGNORE); sd = accept(listen_sd, (struct sockaddr *) &sa_cli, &client_len); printf("- connection from %s, port %d\n", inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)), ntohs(sa_cli.sin_port)); gnutls_transport_set_int(session, sd); do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { close(sd); gnutls_deinit(session); fprintf(stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror(ret)); continue; } printf("- Handshake was completed\n"); /* see the Getting peer's information example */ /* print_info(session); */ for (;;) { ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf ("\n- Peer has closed the GnuTLS connection\n"); break; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "\n*** Received corrupted " "data(%d). Closing the connection.\n\n", ret); break; } else if (ret > 0) { /* echo data back to the client */ gnutls_record_send(session, buffer, ret); } } printf("\n"); /* do not wait for the peer to close the connection. */ gnutls_bye(session, GNUTLS_SHUT_WR); close(sd); gnutls_deinit(session); } close(listen_sd); gnutls_certificate_free_credentials(x509_cred); gnutls_priority_deinit(priority_cache); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Echo server with OpenPGP authentication, Next: Echo server with SRP authentication, Prev: Echo server with X.509 authentication, Up: Server examples 7.2.2 Echo server with OpenPGP authentication --------------------------------------------- The following example is an echo server which supports OpenPGP key authentication. You can easily combine this functionality --that is have a server that supports both X.509 and OpenPGP certificates-- but we separated them to keep these examples as simple as possible. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #define KEYFILE "secret.asc" #define CERTFILE "public.asc" #define RINGFILE "ring.gpg" /* This is a sample TLS 1.0-OpenPGP echo server. */ #define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);} #define MAX_BUF 1024 #define PORT 5556 /* listen to 5556 port */ /* These are global */ gnutls_dh_params_t dh_params; static int generate_dh_params(void) { unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); /* Generate Diffie-Hellman parameters - for use with DHE * kx algorithms. These should be discarded and regenerated * once a day, once a week or once a month. Depending on the * security requirements. */ gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, bits); return 0; } int main(void) { int err, listen_sd; int sd, ret; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; socklen_t client_len; char topbuf[512]; gnutls_session_t session; gnutls_certificate_credentials_t cred; char buffer[MAX_BUF + 1]; int optval = 1; char name[256]; strcpy(name, "Echo Server"); /* this must be called once in the program */ gnutls_global_init(); gnutls_certificate_allocate_credentials(&cred); gnutls_certificate_set_openpgp_keyring_file(cred, RINGFILE, GNUTLS_OPENPGP_FMT_BASE64); gnutls_certificate_set_openpgp_key_file(cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64); generate_dh_params(); gnutls_certificate_set_dh_params(cred, dh_params); /* Socket operations */ listen_sd = socket(AF_INET, SOCK_STREAM, 0); SOCKET_ERR(listen_sd, "socket"); memset(&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons(PORT); /* Server Port number */ setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof(int)); err = bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); SOCKET_ERR(err, "bind"); err = listen(listen_sd, 1024); SOCKET_ERR(err, "listen"); printf("%s ready. Listening to port '%d'.\n\n", name, PORT); client_len = sizeof(sa_cli); for (;;) { gnutls_init(&session, GNUTLS_SERVER); gnutls_priority_set_direct(session, "NORMAL:+CTYPE-OPENPGP", NULL); /* request client certificate if any. */ gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUEST); sd = accept(listen_sd, (struct sockaddr *) &sa_cli, &client_len); printf("- connection from %s, port %d\n", inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)), ntohs(sa_cli.sin_port)); gnutls_transport_set_int(session, sd); ret = gnutls_handshake(session); if (ret < 0) { close(sd); gnutls_deinit(session); fprintf(stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror(ret)); continue; } printf("- Handshake was completed\n"); /* see the Getting peer's information example */ /* print_info(session); */ for (;;) { ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf ("\n- Peer has closed the GnuTLS connection\n"); break; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "\n*** Received corrupted " "data(%d). Closing the connection.\n\n", ret); break; } else if (ret > 0) { /* echo data back to the client */ gnutls_record_send(session, buffer, ret); } } printf("\n"); /* do not wait for the peer to close the connection. */ gnutls_bye(session, GNUTLS_SHUT_WR); close(sd); gnutls_deinit(session); } close(listen_sd); gnutls_certificate_free_credentials(cred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Echo server with SRP authentication, Next: Echo server with anonymous authentication, Prev: Echo server with OpenPGP authentication, Up: Server examples 7.2.3 Echo server with SRP authentication ----------------------------------------- This is a server which supports SRP authentication. It is also possible to combine this functionality with a certificate server. Here it is separate for simplicity. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #define SRP_PASSWD "tpasswd" #define SRP_PASSWD_CONF "tpasswd.conf" #define KEYFILE "key.pem" #define CERTFILE "cert.pem" #define CAFILE "/etc/ssl/certs/ca-certificates.crt" /* This is a sample TLS-SRP echo server. */ #define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);} #define MAX_BUF 1024 #define PORT 5556 /* listen to 5556 port */ int main(void) { int err, listen_sd; int sd, ret; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; socklen_t client_len; char topbuf[512]; gnutls_session_t session; gnutls_srp_server_credentials_t srp_cred; gnutls_certificate_credentials_t cert_cred; char buffer[MAX_BUF + 1]; int optval = 1; char name[256]; strcpy(name, "Echo Server"); gnutls_global_init(); /* SRP_PASSWD a password file (created with the included srptool utility) */ gnutls_srp_allocate_server_credentials(&srp_cred); gnutls_srp_set_server_credentials_file(srp_cred, SRP_PASSWD, SRP_PASSWD_CONF); gnutls_certificate_allocate_credentials(&cert_cred); gnutls_certificate_set_x509_trust_file(cert_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_key_file(cert_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM); /* TCP socket operations */ listen_sd = socket(AF_INET, SOCK_STREAM, 0); SOCKET_ERR(listen_sd, "socket"); memset(&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons(PORT); /* Server Port number */ setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof(int)); err = bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); SOCKET_ERR(err, "bind"); err = listen(listen_sd, 1024); SOCKET_ERR(err, "listen"); printf("%s ready. Listening to port '%d'.\n\n", name, PORT); client_len = sizeof(sa_cli); for (;;) { gnutls_init(&session, GNUTLS_SERVER); gnutls_priority_set_direct(session, "NORMAL:-KX-ALL:+SRP:+SRP-DSS:+SRP-RSA", NULL); gnutls_credentials_set(session, GNUTLS_CRD_SRP, srp_cred); /* for the certificate authenticated ciphersuites. */ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred); /* request client certificate if any. */ gnutls_certificate_server_set_request(session, GNUTLS_CERT_IGNORE); sd = accept(listen_sd, (struct sockaddr *) &sa_cli, &client_len); printf("- connection from %s, port %d\n", inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)), ntohs(sa_cli.sin_port)); gnutls_transport_set_int(session, sd); do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { close(sd); gnutls_deinit(session); fprintf(stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror(ret)); continue; } printf("- Handshake was completed\n"); printf("- User %s was connected\n", gnutls_srp_server_get_username(session)); /* print_info(session); */ for (;;) { ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf ("\n- Peer has closed the GnuTLS connection\n"); break; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "\n*** Received corrupted " "data(%d). Closing the connection.\n\n", ret); break; } else if (ret > 0) { /* echo data back to the client */ gnutls_record_send(session, buffer, ret); } } printf("\n"); /* do not wait for the peer to close the connection. */ gnutls_bye(session, GNUTLS_SHUT_WR); close(sd); gnutls_deinit(session); } close(listen_sd); gnutls_srp_free_server_credentials(srp_cred); gnutls_certificate_free_credentials(cert_cred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Echo server with anonymous authentication, Next: DTLS echo server with X.509 authentication, Prev: Echo server with SRP authentication, Up: Server examples 7.2.4 Echo server with anonymous authentication ----------------------------------------------- This example server supports anonymous authentication, and could be used to serve the example client for anonymous authentication. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include /* This is a sample TLS 1.0 echo server, for anonymous authentication only. */ #define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);} #define MAX_BUF 1024 #define PORT 5556 /* listen to 5556 port */ /* These are global */ static gnutls_dh_params_t dh_params; static int generate_dh_params(void) { unsigned int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); /* Generate Diffie-Hellman parameters - for use with DHE * kx algorithms. These should be discarded and regenerated * once a day, once a week or once a month. Depending on the * security requirements. */ gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, bits); return 0; } int main(void) { int err, listen_sd; int sd, ret; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; socklen_t client_len; char topbuf[512]; gnutls_session_t session; gnutls_anon_server_credentials_t anoncred; char buffer[MAX_BUF + 1]; int optval = 1; /* this must be called once in the program */ gnutls_global_init(); gnutls_anon_allocate_server_credentials(&anoncred); generate_dh_params(); gnutls_anon_set_server_dh_params(anoncred, dh_params); /* Socket operations */ listen_sd = socket(AF_INET, SOCK_STREAM, 0); SOCKET_ERR(listen_sd, "socket"); memset(&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons(PORT); /* Server Port number */ setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval, sizeof(int)); err = bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); SOCKET_ERR(err, "bind"); err = listen(listen_sd, 1024); SOCKET_ERR(err, "listen"); printf("Server ready. Listening to port '%d'.\n\n", PORT); client_len = sizeof(sa_cli); for (;;) { gnutls_init(&session, GNUTLS_SERVER); gnutls_priority_set_direct(session, "NORMAL:+ANON-ECDH:+ANON-DH", NULL); gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); sd = accept(listen_sd, (struct sockaddr *) &sa_cli, &client_len); printf("- connection from %s, port %d\n", inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)), ntohs(sa_cli.sin_port)); gnutls_transport_set_int(session, sd); do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { close(sd); gnutls_deinit(session); fprintf(stderr, "*** Handshake has failed (%s)\n\n", gnutls_strerror(ret)); continue; } printf("- Handshake was completed\n"); /* see the Getting peer's information example */ /* print_info(session); */ for (;;) { ret = gnutls_record_recv(session, buffer, MAX_BUF); if (ret == 0) { printf ("\n- Peer has closed the GnuTLS connection\n"); break; } else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); } else if (ret < 0) { fprintf(stderr, "\n*** Received corrupted " "data(%d). Closing the connection.\n\n", ret); break; } else if (ret > 0) { /* echo data back to the client */ gnutls_record_send(session, buffer, ret); } } printf("\n"); /* do not wait for the peer to close the connection. */ gnutls_bye(session, GNUTLS_SHUT_WR); close(sd); gnutls_deinit(session); } close(listen_sd); gnutls_anon_free_server_credentials(anoncred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: DTLS echo server with X.509 authentication, Prev: Echo server with anonymous authentication, Up: Server examples 7.2.5 DTLS echo server with X.509 authentication ------------------------------------------------ This example is a very simple echo server using Datagram TLS and X.509 authentication. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #define KEYFILE "key.pem" #define CERTFILE "cert.pem" #define CAFILE "/etc/ssl/certs/ca-certificates.crt" #define CRLFILE "crl.pem" /* This is a sample DTLS echo server, using X.509 authentication. * Note that error checking is minimal to simplify the example. */ #define MAX_BUFFER 1024 #define PORT 5556 typedef struct { gnutls_session_t session; int fd; struct sockaddr *cli_addr; socklen_t cli_addr_size; } priv_data_st; static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms); static ssize_t push_func(gnutls_transport_ptr_t p, const void *data, size_t size); static ssize_t pull_func(gnutls_transport_ptr_t p, void *data, size_t size); static const char *human_addr(const struct sockaddr *sa, socklen_t salen, char *buf, size_t buflen); static int wait_for_connection(int fd); static int generate_dh_params(void); /* Use global credentials and parameters to simplify * the example. */ static gnutls_certificate_credentials_t x509_cred; static gnutls_priority_t priority_cache; static gnutls_dh_params_t dh_params; int main(void) { int listen_sd; int sock, ret; struct sockaddr_in sa_serv; struct sockaddr_in cli_addr; socklen_t cli_addr_size; gnutls_session_t session; char buffer[MAX_BUFFER]; priv_data_st priv; gnutls_datum_t cookie_key; gnutls_dtls_prestate_st prestate; int mtu = 1400; unsigned char sequence[8]; /* this must be called once in the program */ gnutls_global_init(); gnutls_certificate_allocate_credentials(&x509_cred); gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM); ret = gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM); if (ret < 0) { printf("No certificate or key were found\n"); exit(1); } generate_dh_params(); gnutls_certificate_set_dh_params(x509_cred, dh_params); gnutls_priority_init(&priority_cache, "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE", NULL); gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE); /* Socket operations */ listen_sd = socket(AF_INET, SOCK_DGRAM, 0); memset(&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons(PORT); { /* DTLS requires the IP don't fragment (DF) bit to be set */ #if defined(IP_DONTFRAG) int optval = 1; setsockopt(listen_sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &optval, sizeof(optval)); #elif defined(IP_MTU_DISCOVER) int optval = IP_PMTUDISC_DO; setsockopt(listen_sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void *) &optval, sizeof(optval)); #endif } bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv)); printf("UDP server ready. Listening to port '%d'.\n\n", PORT); for (;;) { printf("Waiting for connection...\n"); sock = wait_for_connection(listen_sd); if (sock < 0) continue; cli_addr_size = sizeof(cli_addr); ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret > 0) { memset(&prestate, 0, sizeof(prestate)); ret = gnutls_dtls_cookie_verify(&cookie_key, &cli_addr, sizeof(cli_addr), buffer, ret, &prestate); if (ret < 0) { /* cookie not valid */ priv_data_st s; memset(&s, 0, sizeof(s)); s.fd = sock; s.cli_addr = (void *) &cli_addr; s.cli_addr_size = sizeof(cli_addr); printf ("Sending hello verify request to %s\n", human_addr((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); gnutls_dtls_cookie_send(&cookie_key, &cli_addr, sizeof(cli_addr), &prestate, (gnutls_transport_ptr_t) & s, push_func); /* discard peeked data */ recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &cli_addr, &cli_addr_size); usleep(100); continue; } printf("Accepted connection from %s\n", human_addr((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); } else continue; gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM); gnutls_priority_set(session, priority_cache); gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); gnutls_dtls_prestate_set(session, &prestate); gnutls_dtls_set_mtu(session, mtu); priv.session = session; priv.fd = sock; priv.cli_addr = (struct sockaddr *) &cli_addr; priv.cli_addr_size = sizeof(cli_addr); gnutls_transport_set_ptr(session, &priv); gnutls_transport_set_push_function(session, push_func); gnutls_transport_set_pull_function(session, pull_func); gnutls_transport_set_pull_timeout_function(session, pull_timeout_func); do { ret = gnutls_handshake(session); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); /* Note that DTLS may also receive GNUTLS_E_LARGE_PACKET. * In that case the MTU should be adjusted. */ if (ret < 0) { fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret)); gnutls_deinit(session); continue; } printf("- Handshake was completed\n"); for (;;) { do { ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, sequence); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0 && gnutls_error_is_fatal(ret) == 0) { fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); continue; } else if (ret < 0) { fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret)); break; } if (ret == 0) { printf("EOF\n\n"); break; } buffer[ret] = 0; printf ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], buffer); /* reply back */ ret = gnutls_record_send(session, buffer, ret); if (ret < 0) { fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret)); break; } } gnutls_bye(session, GNUTLS_SHUT_WR); gnutls_deinit(session); } close(listen_sd); gnutls_certificate_free_credentials(x509_cred); gnutls_priority_deinit(priority_cache); gnutls_global_deinit(); return 0; } static int wait_for_connection(int fd) { fd_set rd, wr; int n; FD_ZERO(&rd); FD_ZERO(&wr); FD_SET(fd, &rd); /* waiting part */ n = select(fd + 1, &rd, &wr, NULL, NULL); if (n == -1 && errno == EINTR) return -1; if (n < 0) { perror("select()"); exit(1); } return fd; } /* Wait for data to be received within a timeout period in milliseconds */ static int pull_timeout_func(gnutls_transport_ptr_t ptr, unsigned int ms) { fd_set rfds; struct timeval tv; priv_data_st *priv = ptr; struct sockaddr_in cli_addr; socklen_t cli_addr_size; int ret; char c; FD_ZERO(&rfds); FD_SET(priv->fd, &rfds); tv.tv_sec = 0; tv.tv_usec = ms * 1000; while (tv.tv_usec >= 1000000) { tv.tv_usec -= 1000000; tv.tv_sec++; } ret = select(priv->fd + 1, &rfds, NULL, NULL, &tv); if (ret <= 0) return ret; /* only report ok if the next message is from the peer we expect * from */ cli_addr_size = sizeof(cli_addr); ret = recvfrom(priv->fd, &c, 1, MSG_PEEK, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret > 0) { if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0) return 1; } return 0; } static ssize_t push_func(gnutls_transport_ptr_t p, const void *data, size_t size) { priv_data_st *priv = p; return sendto(priv->fd, data, size, 0, priv->cli_addr, priv->cli_addr_size); } static ssize_t pull_func(gnutls_transport_ptr_t p, void *data, size_t size) { priv_data_st *priv = p; struct sockaddr_in cli_addr; socklen_t cli_addr_size; char buffer[64]; int ret; cli_addr_size = sizeof(cli_addr); ret = recvfrom(priv->fd, data, size, 0, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret == -1) return ret; if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr)) == 0) return ret; printf("Denied connection from %s\n", human_addr((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); gnutls_transport_set_errno(priv->session, EAGAIN); return -1; } static const char *human_addr(const struct sockaddr *sa, socklen_t salen, char *buf, size_t buflen) { const char *save_buf = buf; size_t l; if (!buf || !buflen) return NULL; *buf = '\0'; switch (sa->sa_family) { #if HAVE_IPV6 case AF_INET6: snprintf(buf, buflen, "IPv6 "); break; #endif case AF_INET: snprintf(buf, buflen, "IPv4 "); break; } l = strlen(buf); buf += l; buflen -= l; if (getnameinfo(sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0) return NULL; l = strlen(buf); buf += l; buflen -= l; strncat(buf, " port ", buflen); l = strlen(buf); buf += l; buflen -= l; if (getnameinfo(sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0) return NULL; return save_buf; } static int generate_dh_params(void) { int bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY); /* Generate Diffie-Hellman parameters - for use with DHE * kx algorithms. When short bit length is used, it might * be wise to regenerate parameters often. */ gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, bits); return 0; }  File: gnutls.info, Node: OCSP example, Next: Miscellaneous examples, Prev: Server examples, Up: GnuTLS application examples 7.3 OCSP example ================ Generate OCSP request --------------------- A small tool to generate OCSP requests. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #ifndef NO_LIBCURL #include #endif #include "read-file.h" size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp); static gnutls_x509_crt_t load_cert(const char *cert_file); static void _response_info(const gnutls_datum_t * data); static void _generate_request(gnutls_datum_t * rdata, gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, gnutls_datum_t *nonce); static int _verify_response(gnutls_datum_t * data, gnutls_x509_crt_t cert, gnutls_x509_crt_t signer, gnutls_datum_t *nonce); /* This program queries an OCSP server. It expects three files. argv[1] containing the certificate to be checked, argv[2] holding the issuer for this certificate, and argv[3] holding a trusted certificate to verify OCSP's response. argv[4] is optional and should hold the server host name. For simplicity the libcurl library is used. */ int main(int argc, char *argv[]) { gnutls_datum_t ud, tmp; int ret; gnutls_datum_t req; gnutls_x509_crt_t cert, issuer, signer; #ifndef NO_LIBCURL CURL *handle; struct curl_slist *headers = NULL; #endif int v, seq; const char *cert_file = argv[1]; const char *issuer_file = argv[2]; const char *signer_file = argv[3]; char *hostname = NULL; unsigned char noncebuf[23]; gnutls_datum_t nonce = { noncebuf, sizeof(noncebuf) }; gnutls_global_init(); if (argc > 4) hostname = argv[4]; ret = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size); if (ret < 0) exit(1); cert = load_cert(cert_file); issuer = load_cert(issuer_file); signer = load_cert(signer_file); if (hostname == NULL) { for (seq = 0;; seq++) { ret = gnutls_x509_crt_get_authority_info_access(cert, seq, GNUTLS_IA_OCSP_URI, &tmp, NULL); if (ret == GNUTLS_E_UNKNOWN_ALGORITHM) continue; if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { fprintf(stderr, "No URI was found in the certificate.\n"); exit(1); } if (ret < 0) { fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); exit(1); } printf("CA issuers URI: %.*s\n", tmp.size, tmp.data); hostname = malloc(tmp.size + 1); memcpy(hostname, tmp.data, tmp.size); hostname[tmp.size] = 0; gnutls_free(tmp.data); break; } } /* Note that the OCSP servers hostname might be available * using gnutls_x509_crt_get_authority_info_access() in the issuer's * certificate */ memset(&ud, 0, sizeof(ud)); fprintf(stderr, "Connecting to %s\n", hostname); _generate_request(&req, cert, issuer, &nonce); #ifndef NO_LIBCURL curl_global_init(CURL_GLOBAL_ALL); handle = curl_easy_init(); if (handle == NULL) exit(1); headers = curl_slist_append(headers, "Content-Type: application/ocsp-request"); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(handle, CURLOPT_POSTFIELDS, (void *) req.data); curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, req.size); curl_easy_setopt(handle, CURLOPT_URL, hostname); curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, get_data); curl_easy_setopt(handle, CURLOPT_WRITEDATA, &ud); ret = curl_easy_perform(handle); if (ret != 0) { fprintf(stderr, "curl[%d] error %d\n", __LINE__, ret); exit(1); } curl_easy_cleanup(handle); #endif _response_info(&ud); v = _verify_response(&ud, cert, signer, &nonce); gnutls_x509_crt_deinit(cert); gnutls_x509_crt_deinit(issuer); gnutls_x509_crt_deinit(signer); gnutls_global_deinit(); return v; } static void _response_info(const gnutls_datum_t * data) { gnutls_ocsp_resp_t resp; int ret; gnutls_datum buf; ret = gnutls_ocsp_resp_init(&resp); if (ret < 0) exit(1); ret = gnutls_ocsp_resp_import(resp, data); if (ret < 0) exit(1); ret = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf); if (ret != 0) exit(1); printf("%.*s", buf.size, buf.data); gnutls_free(buf.data); gnutls_ocsp_resp_deinit(resp); } static gnutls_x509_crt_t load_cert(const char *cert_file) { gnutls_x509_crt_t crt; int ret; gnutls_datum_t data; size_t size; ret = gnutls_x509_crt_init(&crt); if (ret < 0) exit(1); data.data = (void *) read_binary_file(cert_file, &size); data.size = size; if (!data.data) { fprintf(stderr, "Cannot open file: %s\n", cert_file); exit(1); } ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM); free(data.data); if (ret < 0) { fprintf(stderr, "Cannot import certificate in %s: %s\n", cert_file, gnutls_strerror(ret)); exit(1); } return crt; } static void _generate_request(gnutls_datum_t * rdata, gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, gnutls_datum_t *nonce) { gnutls_ocsp_req_t req; int ret; ret = gnutls_ocsp_req_init(&req); if (ret < 0) exit(1); ret = gnutls_ocsp_req_add_cert(req, GNUTLS_DIG_SHA1, issuer, cert); if (ret < 0) exit(1); ret = gnutls_ocsp_req_set_nonce(req, 0, nonce); if (ret < 0) exit(1); ret = gnutls_ocsp_req_export(req, rdata); if (ret != 0) exit(1); gnutls_ocsp_req_deinit(req); return; } static int _verify_response(gnutls_datum_t * data, gnutls_x509_crt_t cert, gnutls_x509_crt_t signer, gnutls_datum_t *nonce) { gnutls_ocsp_resp_t resp; int ret; unsigned verify; gnutls_datum_t rnonce; ret = gnutls_ocsp_resp_init(&resp); if (ret < 0) exit(1); ret = gnutls_ocsp_resp_import(resp, data); if (ret < 0) exit(1); ret = gnutls_ocsp_resp_check_crt(resp, 0, cert); if (ret < 0) exit(1); ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce); if (ret < 0) exit(1); if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data, nonce->size) != 0) { exit(1); } ret = gnutls_ocsp_resp_verify_direct(resp, signer, &verify, 0); if (ret < 0) exit(1); printf("Verifying OCSP Response: "); if (verify == 0) printf("Verification success!\n"); else printf("Verification error!\n"); if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND) printf("Signer cert not found\n"); if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR) printf("Signer cert keyusage error\n"); if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER) printf("Signer cert is not trusted\n"); if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM) printf("Insecure algorithm\n"); if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE) printf("Signature failure\n"); if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED) printf("Signer cert not yet activated\n"); if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED) printf("Signer cert expired\n"); gnutls_free(rnonce.data); gnutls_ocsp_resp_deinit(resp); return verify; } size_t get_data(void *buffer, size_t size, size_t nmemb, void *userp) { gnutls_datum_t *ud = userp; size *= nmemb; ud->data = realloc(ud->data, size + ud->size); if (ud->data == NULL) { fprintf(stderr, "Not enough memory for the request\n"); exit(1); } memcpy(&ud->data[ud->size], buffer, size); ud->size += size; return size; }  File: gnutls.info, Node: Miscellaneous examples, Next: XSSL examples, Prev: OCSP example, Up: GnuTLS application examples 7.4 Miscellaneous examples ========================== * Menu: * Checking for an alert:: * X.509 certificate parsing example:: * Listing the ciphersuites in a priority string:: * PKCS12 structure generation example::  File: gnutls.info, Node: Checking for an alert, Next: X.509 certificate parsing example, Up: Miscellaneous examples 7.4.1 Checking for an alert --------------------------- This is a function that checks if an alert has been received in the current session. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "examples.h" /* This function will check whether the given return code from * a gnutls function (recv/send), is an alert, and will print * that alert. */ void check_alert(gnutls_session_t session, int ret) { int last_alert; if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { last_alert = gnutls_alert_get(session); /* The check for renegotiation is only useful if we are * a server, and we had requested a rehandshake. */ if (last_alert == GNUTLS_A_NO_RENEGOTIATION && ret == GNUTLS_E_WARNING_ALERT_RECEIVED) printf("* Received NO_RENEGOTIATION alert. " "Client Does not support renegotiation.\n"); else printf("* Received alert '%d': %s.\n", last_alert, gnutls_alert_get_name(last_alert)); } }  File: gnutls.info, Node: X.509 certificate parsing example, Next: Listing the ciphersuites in a priority string, Prev: Checking for an alert, Up: Miscellaneous examples 7.4.2 X.509 certificate parsing example --------------------------------------- To demonstrate the X.509 parsing capabilities an example program is listed below. That program reads the peer's certificate, and prints information about it. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "examples.h" static const char *bin2hex(const void *bin, size_t bin_size) { static char printable[110]; const unsigned char *_bin = bin; char *print; size_t i; if (bin_size > 50) bin_size = 50; print = printable; for (i = 0; i < bin_size; i++) { sprintf(print, "%.2x ", _bin[i]); print += 2; } return printable; } /* This function will print information about this session's peer * certificate. */ void print_x509_certificate_info(gnutls_session_t session) { char serial[40]; char dn[256]; size_t size; unsigned int algo, bits; time_t expiration_time, activation_time; const gnutls_datum_t *cert_list; unsigned int cert_list_size = 0; gnutls_x509_crt_t cert; gnutls_datum_t cinfo; /* This function only works for X.509 certificates. */ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) return; cert_list = gnutls_certificate_get_peers(session, &cert_list_size); printf("Peer provided %d certificates.\n", cert_list_size); if (cert_list_size > 0) { int ret; /* we only print information about the first certificate. */ gnutls_x509_crt_init(&cert); gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER); printf("Certificate info:\n"); /* This is the preferred way of printing short information about a certificate. */ ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo); if (ret == 0) { printf("\t%s\n", cinfo.data); gnutls_free(cinfo.data); } /* If you want to extract fields manually for some other reason, below are popular example calls. */ expiration_time = gnutls_x509_crt_get_expiration_time(cert); activation_time = gnutls_x509_crt_get_activation_time(cert); printf("\tCertificate is valid since: %s", ctime(&activation_time)); printf("\tCertificate expires: %s", ctime(&expiration_time)); /* Print the serial number of the certificate. */ size = sizeof(serial); gnutls_x509_crt_get_serial(cert, serial, &size); printf("\tCertificate serial number: %s\n", bin2hex(serial, size)); /* Extract some of the public key algorithm's parameters */ algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits); printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo)); /* Print the version of the X.509 * certificate. */ printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert)); size = sizeof(dn); gnutls_x509_crt_get_dn(cert, dn, &size); printf("\tDN: %s\n", dn); size = sizeof(dn); gnutls_x509_crt_get_issuer_dn(cert, dn, &size); printf("\tIssuer's DN: %s\n", dn); gnutls_x509_crt_deinit(cert); } }  File: gnutls.info, Node: Listing the ciphersuites in a priority string, Next: PKCS12 structure generation example, Prev: X.509 certificate parsing example, Up: Miscellaneous examples 7.4.3 Listing the ciphersuites in a priority string --------------------------------------------------- This is a small program to list the enabled ciphersuites by a priority string. /* This example code is placed in the public domain. */ #include #include #include #include #include static void print_cipher_suite_list(const char *priorities) { size_t i; int ret; unsigned int idx; const char *name; const char *err; unsigned char id[2]; gnutls_protocol_t version; gnutls_priority_t pcache; if (priorities != NULL) { printf("Cipher suites for %s\n", priorities); ret = gnutls_priority_init(&pcache, priorities, &err); if (ret < 0) { fprintf(stderr, "Syntax error at: %s\n", err); exit(1); } for (i = 0;; i++) { ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) continue; name = gnutls_cipher_suite_info(idx, id, NULL, NULL, NULL, &version); if (name != NULL) printf("%-50s\t0x%02x, 0x%02x\t%s\n", name, (unsigned char) id[0], (unsigned char) id[1], gnutls_protocol_get_name(version)); } return; } } int main(int argc, char **argv) { if (argc > 1) print_cipher_suite_list(argv[1]); return 0; }  File: gnutls.info, Node: PKCS12 structure generation example, Prev: Listing the ciphersuites in a priority string, Up: Miscellaneous examples 7.4.4 PKCS #12 structure generation example ------------------------------------------- This small program demonstrates the usage of the PKCS #12 API, by generating such a structure. /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "examples.h" #define OUTFILE "out.p12" /* This function will write a pkcs12 structure into a file. * cert: is a DER encoded certificate * pkcs8_key: is a PKCS #8 encrypted key (note that this must be * encrypted using a PKCS #12 cipher, or some browsers will crash) * password: is the password used to encrypt the PKCS #12 packet. */ int write_pkcs12(const gnutls_datum_t * cert, const gnutls_datum_t * pkcs8_key, const char *password) { gnutls_pkcs12_t pkcs12; int ret, bag_index; gnutls_pkcs12_bag_t bag, key_bag; char pkcs12_struct[10 * 1024]; size_t pkcs12_struct_size; FILE *fd; /* A good idea might be to use gnutls_x509_privkey_get_key_id() * to obtain a unique ID. */ gnutls_datum_t key_id = { (void *) "\x00\x00\x07", 3 }; gnutls_global_init(); /* Firstly we create two helper bags, which hold the certificate, * and the (encrypted) key. */ gnutls_pkcs12_bag_init(&bag); gnutls_pkcs12_bag_init(&key_bag); ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CERTIFICATE, cert); if (ret < 0) { fprintf(stderr, "ret: %s\n", gnutls_strerror(ret)); return 1; } /* ret now holds the bag's index. */ bag_index = ret; /* Associate a friendly name with the given certificate. Used * by browsers. */ gnutls_pkcs12_bag_set_friendly_name(bag, bag_index, "My name"); /* Associate the certificate with the key using a unique key * ID. */ gnutls_pkcs12_bag_set_key_id(bag, bag_index, &key_id); /* use weak encryption for the certificate. */ gnutls_pkcs12_bag_encrypt(bag, password, GNUTLS_PKCS_USE_PKCS12_RC2_40); /* Now the key. */ ret = gnutls_pkcs12_bag_set_data(key_bag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, pkcs8_key); if (ret < 0) { fprintf(stderr, "ret: %s\n", gnutls_strerror(ret)); return 1; } /* Note that since the PKCS #8 key is already encrypted we don't * bother encrypting that bag. */ bag_index = ret; gnutls_pkcs12_bag_set_friendly_name(key_bag, bag_index, "My name"); gnutls_pkcs12_bag_set_key_id(key_bag, bag_index, &key_id); /* The bags were filled. Now create the PKCS #12 structure. */ gnutls_pkcs12_init(&pkcs12); /* Insert the two bags in the PKCS #12 structure. */ gnutls_pkcs12_set_bag(pkcs12, bag); gnutls_pkcs12_set_bag(pkcs12, key_bag); /* Generate a message authentication code for the PKCS #12 * structure. */ gnutls_pkcs12_generate_mac(pkcs12, password); pkcs12_struct_size = sizeof(pkcs12_struct); ret = gnutls_pkcs12_export(pkcs12, GNUTLS_X509_FMT_DER, pkcs12_struct, &pkcs12_struct_size); if (ret < 0) { fprintf(stderr, "ret: %s\n", gnutls_strerror(ret)); return 1; } fd = fopen(OUTFILE, "w"); if (fd == NULL) { fprintf(stderr, "cannot open file\n"); return 1; } fwrite(pkcs12_struct, 1, pkcs12_struct_size, fd); fclose(fd); gnutls_pkcs12_bag_deinit(bag); gnutls_pkcs12_bag_deinit(key_bag); gnutls_pkcs12_deinit(pkcs12); return 0; }  File: gnutls.info, Node: XSSL examples, Prev: Miscellaneous examples, Up: GnuTLS application examples 7.5 XSSL examples ================= XSSL is an experimental API available in the 'gnutls-xssl' library and in 'gnutls/xssl.h' header. It is intended to be a very simple to use API avoid the GnuTLS API. The API however has the following limitations * It is applicable to blocking sockets only. * The server verification is based on its DNS name. * Menu: * Example client with X.509 certificate authentication:: * Example client with X.509 certificate authentication and TOFU::  File: gnutls.info, Node: Example client with X.509 certificate authentication, Next: Example client with X.509 certificate authentication and TOFU, Up: XSSL examples 7.5.1 Example client with X.509 certificate authentication ---------------------------------------------------------- /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "examples.h" /* A simple TLS client, with X.509 authentication. Certificate verification * is explicit. */ extern int tcp_connect(void); extern void tcp_close(int sd); int main(void) { int ret; char *line = NULL; size_t line_len; xssl_cred_t cred; xssl_t sb; unsigned int status; int fd; gnutls_global_init(); fd = tcp_connect(); ret = xssl_cred_init(&cred, GNUTLS_VMETHOD_SYSTEM_CAS, NULL, 0); if (ret < 0) exit(1); /* Initialize TLS session */ ret = xssl_client_init(&sb, "www.example.com", NULL, (gnutls_transport_ptr_t) fd, NULL, cred, &status, 0); if (ret < 0) { if (ret == GNUTLS_E_AUTH_ERROR) { gnutls_datum_t txt; gnutls_certificate_verification_status_print (status, GNUTLS_CRT_X509, &txt, 0); fprintf(stderr, "Verification error (%x): %s\n", status, txt.data); gnutls_free(txt.data); } exit(1); } #define REQ "GET / HTTP/1.0\r\n" ret = xssl_write(sb, REQ, sizeof(REQ) - 1); if (ret < 0) exit(1); do { ret = xssl_getline(sb, &line, &line_len); if (ret < 0) exit(1); fprintf(stderr, "received: %s\n", line); } while (ret >= 0); gnutls_free(line); xssl_deinit(sb); tcp_close(fd); xssl_cred_deinit(cred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Example client with X.509 certificate authentication and TOFU, Prev: Example client with X.509 certificate authentication, Up: XSSL examples 7.5.2 Example client with X.509 certificate authentication and TOFU ------------------------------------------------------------------- /* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "examples.h" /* A simple TLS client, with X.509 authentication. Certificate verification * with a fixed CA, and trust on first use. */ extern int tcp_connect(void); extern void tcp_close(int sd); int main(void) { int ret; char *line = NULL; size_t line_len; xssl_cred_t cred; xssl_t sb; gnutls_cinput_st aux[2]; unsigned aux_size = 0; unsigned int status; int fd; gnutls_global_init(); fd = tcp_connect(); aux[aux_size].type = GNUTLS_CINPUT_TYPE_FILE; aux[aux_size].contents = GNUTLS_CINPUT_CAS; aux[aux_size].fmt = GNUTLS_X509_FMT_PEM; aux[aux_size].i1.file = "/path/to/ca/file"; aux_size++; /* This may be skipped to use the default DB file */ aux[aux_size].type = GNUTLS_CINPUT_TYPE_FILE; aux[aux_size].contents = GNUTLS_CINPUT_TOFU_DB; aux[aux_size].i1.file = "/path/to/trust/db/file"; aux_size++; ret = xssl_cred_init(&cred, GNUTLS_VMETHOD_GIVEN_CAS | GNUTLS_VMETHOD_TOFU, aux, aux_size); if (ret < 0) exit(1); /* Initialize TLS session */ ret = xssl_client_init(&sb, "www.example.com", NULL, (gnutls_transport_ptr_t) fd, NULL, cred, &status, 0); if (ret < 0) { if (ret == GNUTLS_E_AUTH_ERROR) { gnutls_datum_t txt; gnutls_certificate_verification_status_print (status, GNUTLS_CRT_X509, &txt, 0); fprintf(stderr, "Verification error (%x): %s\n", status, txt.data); gnutls_free(txt.data); } exit(1); } #define REQ "GET / HTTP/1.0\r\n" ret = xssl_write(sb, REQ, sizeof(REQ) - 1); if (ret < 0) exit(1); do { ret = xssl_getline(sb, &line, &line_len); if (ret < 0) exit(1); fprintf(stderr, "received: %s\n", line); } while (ret >= 0); gnutls_free(line); xssl_deinit(sb); tcp_close(fd); xssl_cred_deinit(cred); gnutls_global_deinit(); return 0; }  File: gnutls.info, Node: Using GnuTLS as a cryptographic library, Next: Other included programs, Prev: GnuTLS application examples, Up: Top 8 Using GnuTLS as a cryptographic library ***************************************** GnuTLS is not a low-level cryptographic library, i.e., it does not provide access to basic cryptographic primitives. However it abstracts the internal cryptographic back-end (see *note Cryptographic Backend::), providing symmetric crypto, hash and HMAC algorithms, as well access to the random number generation. * Menu: * Symmetric algorithms:: * Public key algorithms:: * Hash and HMAC functions:: * Random number generation::  File: gnutls.info, Node: Symmetric algorithms, Next: Public key algorithms, Up: Using GnuTLS as a cryptographic library 8.1 Symmetric algorithms ======================== The available functions to access symmetric crypto algorithms operations are shown below. The supported algorithms are the algorithms required by the TLS protocol. They are listed in *note Table 3.1: tab:ciphers. 'INT *note gnutls_cipher_init:: (gnutls_cipher_hd_t * HANDLE, gnutls_cipher_algorithm_t CIPHER, const gnutls_datum_t * KEY, const gnutls_datum_t * IV)' 'INT *note gnutls_cipher_encrypt2:: (gnutls_cipher_hd_t HANDLE, const void * TEXT, size_t TEXTLEN, void * CIPHERTEXT, size_t CIPHERTEXTLEN)' 'INT *note gnutls_cipher_decrypt2:: (gnutls_cipher_hd_t HANDLE, const void * CIPHERTEXT, size_t CIPHERTEXTLEN, void * TEXT, size_t TEXTLEN)' 'VOID *note gnutls_cipher_set_iv:: (gnutls_cipher_hd_t HANDLE, void * IV, size_t IVLEN)' 'VOID *note gnutls_cipher_deinit:: (gnutls_cipher_hd_t HANDLE)' In order to support authenticated encryption with associated data (AEAD) algorithms the following functions are provided to set the associated data and retrieve the authentication tag. 'INT *note gnutls_cipher_add_auth:: (gnutls_cipher_hd_t HANDLE, const void * TEXT, size_t TEXT_SIZE)' 'INT *note gnutls_cipher_tag:: (gnutls_cipher_hd_t HANDLE, void * TAG, size_t TAG_SIZE)'  File: gnutls.info, Node: Public key algorithms, Next: Hash and HMAC functions, Prev: Symmetric algorithms, Up: Using GnuTLS as a cryptographic library 8.2 Public key algorithms ========================= Public key cryptography algorithms such as RSA, DSA and ECDSA, can be accessed using the abstract key API in *note Abstract key types::. This is a high level API with the advantage of transparently handling keys in memory and keys present in smart cards.  File: gnutls.info, Node: Hash and HMAC functions, Next: Random number generation, Prev: Public key algorithms, Up: Using GnuTLS as a cryptographic library 8.3 Hash and HMAC functions =========================== The available operations to access hash functions and hash-MAC (HMAC) algorithms are shown below. HMAC algorithms provided keyed hash functionality. They supported HMAC algorithms are listed in *note Table 3.2: tab:macs. 'INT *note gnutls_hmac_init:: (gnutls_hmac_hd_t * DIG, gnutls_mac_algorithm_t ALGORITHM, const void * KEY, size_t KEYLEN)' 'INT *note gnutls_hmac:: (gnutls_hmac_hd_t HANDLE, const void * TEXT, size_t TEXTLEN)' 'VOID *note gnutls_hmac_output:: (gnutls_hmac_hd_t HANDLE, void * DIGEST)' 'VOID *note gnutls_hmac_deinit:: (gnutls_hmac_hd_t HANDLE, void * DIGEST)' 'INT *note gnutls_hmac_get_len:: (gnutls_mac_algorithm_t ALGORITHM)' 'INT *note gnutls_hmac_fast:: (gnutls_mac_algorithm_t ALGORITHM, const void * KEY, size_t KEYLEN, const void * TEXT, size_t TEXTLEN, void * DIGEST)' The available functions to access hash functions are shown below. The supported hash functions are the same as the HMAC algorithms. 'INT *note gnutls_hash_init:: (gnutls_hash_hd_t * DIG, gnutls_digest_algorithm_t ALGORITHM)' 'INT *note gnutls_hash:: (gnutls_hash_hd_t HANDLE, const void * TEXT, size_t TEXTLEN)' 'VOID *note gnutls_hash_output:: (gnutls_hash_hd_t HANDLE, void * DIGEST)' 'VOID *note gnutls_hash_deinit:: (gnutls_hash_hd_t HANDLE, void * DIGEST)' 'INT *note gnutls_hash_get_len:: (gnutls_digest_algorithm_t ALGORITHM)' 'INT *note gnutls_hash_fast:: (gnutls_digest_algorithm_t ALGORITHM, const void * TEXT, size_t TEXTLEN, void * DIGEST)' 'INT *note gnutls_fingerprint:: (gnutls_digest_algorithm_t ALGO, const gnutls_datum_t * DATA, void * RESULT, size_t * RESULT_SIZE)'  File: gnutls.info, Node: Random number generation, Prev: Hash and HMAC functions, Up: Using GnuTLS as a cryptographic library 8.4 Random number generation ============================ Access to the random number generator is provided using the *note gnutls_rnd:: function. It allows obtaining random data of various levels. 'GNUTLS_RND_NONCE' Non-predictable random number. Fatal in parts of session if broken, i.e., vulnerable to statistical analysis. 'GNUTLS_RND_RANDOM' Pseudo-random cryptographic random number. Fatal in session if broken. 'GNUTLS_RND_KEY' Fatal in many sessions if broken. Figure 8.1: The random number levels. -- Function: int gnutls_rnd (gnutls_rnd_level_t LEVEL, void * DATA, size_t LEN) LEVEL: a security level DATA: place to store random bytes LEN: The requested size This function will generate random data and store it to output buffer. *Returns:* Zero or a negative error code on error. *Since:* 2.12.0  File: gnutls.info, Node: Other included programs, Next: Internal architecture of GnuTLS, Prev: Using GnuTLS as a cryptographic library, Up: Top 9 Other included programs ************************* Included with GnuTLS are also a few command line tools that let you use the library for common tasks without writing an application. The applications are discussed in this chapter. * Menu: * gnutls-cli Invocation:: Invoking gnutls-cli * gnutls-serv Invocation:: Invoking gnutls-serv * gnutls-cli-debug Invocation:: Invoking gnutls-cli-debug  File: gnutls.info, Node: gnutls-cli Invocation, Next: gnutls-serv Invocation, Up: Other included programs 9.1 Invoking gnutls-cli ======================= Simple client program to set up a TLS connection to some other computer. It sets up a TLS connection and forwards data from the standard input to the secured socket and vice versa. This section was generated by *AutoGen*, using the 'agtexi-cmd' template and the option descriptions for the 'gnutls-cli' program. This software is released under the GNU General Public License, version 3 or later. gnutls-cli help/usage ('--help') -------------------------------- This is the automatically generated usage text for gnutls-cli. The text printed is the same whether selected with the 'help' option ('--help') or the 'more-help' option ('--more-help'). 'more-help' will print the usage text by passing it through a pager program. 'more-help' is disabled on platforms without a working 'fork(2)' function. The 'PAGER' environment variable is used to select the program, defaulting to 'more'. Both will exit with a status code of 0. gnutls-cli - GnuTLS client Usage: gnutls-cli [ - [] | --[{=| }] ]... [hostname] -d, --debug=num Enable debugging - it must be in the range: 0 to 9999 -V, --verbose More verbose output - may appear multiple times --tofu Enable trust on first use authentication - disabled as '--no-tofu' --strict-tofu Fail to connect if a known certificate has changed - disabled as '--no-strict-tofu' --dane Enable DANE certificate verification (DNSSEC) - disabled as '--no-dane' --local-dns Use the local DNS server for DNSSEC resolving - disabled as '--no-local-dns' --ca-verification Disable CA certificate verification - disabled as '--no-ca-verification' - enabled by default --ocsp Enable OCSP certificate verification - disabled as '--no-ocsp' -r, --resume Establish a session and resume -e, --rehandshake Establish a session and rehandshake -s, --starttls Connect, establish a plain session and start TLS -u, --udp Use DTLS (datagram TLS) over UDP --mtu=num Set MTU for datagram TLS - it must be in the range: 0 to 17000 --crlf Send CR LF instead of LF --x509fmtder Use DER format for certificates to read from -f, --fingerprint Send the openpgp fingerprint, instead of the key --print-cert Print peer's certificate in PEM format --dh-bits=num The minimum number of bits allowed for DH --priority=str Priorities string --x509cafile=str Certificate file or PKCS #11 URL to use --x509crlfile=file CRL file to use - file must pre-exist --pgpkeyfile=file PGP Key file to use - file must pre-exist --pgpkeyring=file PGP Key ring file to use - file must pre-exist --pgpcertfile=file PGP Public Key (certificate) file to use - file must pre-exist --x509keyfile=str X.509 key file or PKCS #11 URL to use --x509certfile=str X.509 Certificate file or PKCS #11 URL to use --pgpsubkey=str PGP subkey to use (hex or auto) --srpusername=str SRP username to use --srppasswd=str SRP password to use --pskusername=str PSK username to use --pskkey=str PSK key (in hex) to use -p, --port=str The port or service to connect to --insecure Don't abort program if server certificate can't be validated --ranges Use length-hiding padding to prevent traffic analysis --benchmark-ciphers Benchmark individual ciphers --benchmark-soft-ciphers Benchmark individual software ciphers (no hw acceleration) --benchmark-tls-kx Benchmark TLS key exchange methods --benchmark-tls-ciphers Benchmark TLS ciphers -l, --list Print a list of the supported algorithms and modes --noticket Don't allow session tickets --srtp-profiles=str Offer SRTP profiles -!, --alpn=str Application layer protocol - may appear multiple times -b, --heartbeat Activate heartbeat support -", --recordsize=num The maximum record size to advertize - it must be in the range: 0 to 4096 -#, --disable-sni Do not send a Server Name Indication (SNI) -$, --disable-extensions Disable all the TLS extensions -%, --inline-commands Inline commands of the form ^^ -&, --inline-commands-prefix=str Change the default (^) used as a delimiter for inline commands. The value is a single US-ASCII character (octets 0 - 127). -v, --version[=arg] output version information and exit -h, --help display extended usage information and exit -!, --more-help extended usage information passed thru pager Options are specified by doubled hyphens and their name or by a single hyphen and the flag character. Operands and options may be intermixed. They will be reordered. Simple client program to set up a TLS connection to some other computer. It sets up a TLS connection and forwards data from the standard input to the secured socket and vice versa. Please send bug reports to: <@PACKAGE_BUGREPORT@> debug option (-d) ----------------- This is the "enable debugging" option. This option takes a number argument. Specifies the debug level. tofu option ----------- This is the "enable trust on first use authentication" option. This option has some usage constraints. It: * can be disabled with -no-tofu. This option will, in addition to certificate authentication, perform authentication based on previously seen public keys, a model similar to SSH authentication. strict-tofu option ------------------ This is the "fail to connect if a known certificate has changed" option. This option has some usage constraints. It: * can be disabled with -no-strict-tofu. This option will perform authentication as with option -tofu; however, while -tofu asks whether to trust a changed certificate, this option will fail in case of certificate changes. dane option ----------- This is the "enable dane certificate verification (dnssec)" option. This option has some usage constraints. It: * can be disabled with -no-dane. This option will, in addition to certificate authentication using the trusted CAs, verify the server certificates using on the DANE information available via DNSSEC. local-dns option ---------------- This is the "use the local dns server for dnssec resolving" option. This option has some usage constraints. It: * can be disabled with -no-local-dns. This option will use the local DNS server for DNSSEC. This is disabled by default due to many servers not allowing DNSSEC. ca-verification option ---------------------- This is the "disable ca certificate verification" option. This option has some usage constraints. It: * can be disabled with -no-ca-verification. * It is enabled by default. This option will disable CA certificate verification. It is to be used with the -dane or -tofu options. ocsp option ----------- This is the "enable ocsp certificate verification" option. This option has some usage constraints. It: * can be disabled with -no-ocsp. This option will enable verification of the peer's certificate using ocsp resume option (-r) ------------------ This is the "establish a session and resume" option. Connect, establish a session, reconnect and resume. rehandshake option (-e) ----------------------- This is the "establish a session and rehandshake" option. Connect, establish a session and rehandshake immediately. starttls option (-s) -------------------- This is the "connect, establish a plain session and start tls" option. The TLS session will be initiated when EOF or a SIGALRM is received. dh-bits option -------------- This is the "the minimum number of bits allowed for dh" option. This option takes a number argument. This option sets the minimum number of bits allowed for a Diffie-Hellman key exchange. You may want to lower the default value if the peer sends a weak prime and you get an connection error with unacceptable prime. priority option --------------- This is the "priorities string" option. This option takes a string argument. TLS algorithms and protocols to enable. You can use predefined sets of ciphersuites such as PERFORMANCE, NORMAL, PFS, SECURE128, SECURE256. The default is NORMAL. Check the GnuTLS manual on section "Priority strings" for more information on the allowed keywords ranges option ------------- This is the "use length-hiding padding to prevent traffic analysis" option. When possible (e.g., when %NEW_PADDING is specified), use length-hiding padding to prevent traffic analysis. list option (-l) ---------------- This is the "print a list of the supported algorithms and modes" option. Print a list of the supported algorithms and modes. If a priority string is given then only the enabled ciphersuites are shown. alpn option ----------- This is the "application layer protocol" option. This option takes a string argument. This option has some usage constraints. It: * may appear an unlimited number of times. This option will set and enable the Application Layer Protocol Negotiation (ALPN) in the TLS protocol. disable-extensions option ------------------------- This is the "disable all the tls extensions" option. This option disables all TLS extensions. Deprecated option. Use the priority string. inline-commands option ---------------------- This is the "inline commands of the form ^^" option. Enable inline commands of the form ^^. The inline commands are expected to be in a line by themselves. The available commands are: resume and renegotiate. inline-commands-prefix option ----------------------------- This is the "change the default (^) used as a delimiter for inline commands. the value is a single us-ascii character (octets 0 - 127)." option. This option takes a string argument. Change the default (^) delimiter used for inline commands. The delimiter is expected to be a single US-ASCII character (octets 0 - 127). This option is only relevant if inline commands are enabled via the inline-commands option gnutls-cli exit status ---------------------- One of the following exit values will be returned: '0 (EXIT_SUCCESS)' Successful program execution. '1 (EXIT_FAILURE)' The operation failed or the command syntax was not valid. gnutls-cli See Also ------------------- gnutls-cli-debug(1), gnutls-serv(1) gnutls-cli Examples ------------------- Connecting using PSK authentication ----------------------------------- To connect to a server using PSK authentication, you need to enable the choice of PSK by using a cipher priority parameter such as in the example below. $ ./gnutls-cli -p 5556 localhost --pskusername psk_identity \ --pskkey 88f3824b3e5659f52d00e959bacab954b6540344 \ --priority NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK Resolving 'localhost'... Connecting to '127.0.0.1:5556'... - PSK authentication. - Version: TLS1.1 - Key Exchange: PSK - Cipher: AES-128-CBC - MAC: SHA1 - Compression: NULL - Handshake was completed - Simple Client Mode: By keeping the -pskusername parameter and removing the -pskkey parameter, it will query only for the password during the handshake. Listing ciphersuites in a priority string ----------------------------------------- To list the ciphersuites in a priority string: $ ./gnutls-cli --priority SECURE192 -l Cipher suites for SECURE192 TLS_ECDHE_ECDSA_AES_256_CBC_SHA384 0xc0, 0x24 TLS1.2 TLS_ECDHE_ECDSA_AES_256_GCM_SHA384 0xc0, 0x2e TLS1.2 TLS_ECDHE_RSA_AES_256_GCM_SHA384 0xc0, 0x30 TLS1.2 TLS_DHE_RSA_AES_256_CBC_SHA256 0x00, 0x6b TLS1.2 TLS_DHE_DSS_AES_256_CBC_SHA256 0x00, 0x6a TLS1.2 TLS_RSA_AES_256_CBC_SHA256 0x00, 0x3d TLS1.2 Certificate types: CTYPE-X.509 Protocols: VERS-TLS1.2, VERS-TLS1.1, VERS-TLS1.0, VERS-SSL3.0, VERS-DTLS1.0 Compression: COMP-NULL Elliptic curves: CURVE-SECP384R1, CURVE-SECP521R1 PK-signatures: SIGN-RSA-SHA384, SIGN-ECDSA-SHA384, SIGN-RSA-SHA512, SIGN-ECDSA-SHA512 Connecting using a PKCS #11 token --------------------------------- To connect to a server using a certificate and a private key present in a PKCS #11 token you need to substitute the PKCS 11 URLs in the x509certfile and x509keyfile parameters. Those can be found using "p11tool -list-tokens" and then listing all the objects in the needed token, and using the appropriate. $ p11tool --list-tokens Token 0: URL: pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test Label: Test Manufacturer: EnterSafe Model: PKCS15 Serial: 1234 $ p11tool --login --list-certs "pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test" Object 0: URL: pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test;object=client;object-type=cert Type: X.509 Certificate Label: client ID: 2a:97:0d:58:d1:51:3c:23:07:ae:4e:0d:72:26:03:7d:99:06:02:6a $ export MYCERT="pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test;object=client;object-type=cert" $ export MYKEY="pkcs11:model=PKCS15;manufacturer=MyMan;serial=1234;token=Test;object=client;object-type=private" $ gnutls-cli www.example.com --x509keyfile $MYKEY --x509certfile MYCERT Notice that the private key only differs from the certificate in the object-type.  File: gnutls.info, Node: gnutls-serv Invocation, Next: gnutls-cli-debug Invocation, Prev: gnutls-cli Invocation, Up: Other included programs 9.2 Invoking gnutls-serv ======================== Server program that listens to incoming TLS connections. This section was generated by *AutoGen*, using the 'agtexi-cmd' template and the option descriptions for the 'gnutls-serv' program. This software is released under the GNU General Public License, version 3 or later. gnutls-serv help/usage ('--help') --------------------------------- This is the automatically generated usage text for gnutls-serv. The text printed is the same whether selected with the 'help' option ('--help') or the 'more-help' option ('--more-help'). 'more-help' will print the usage text by passing it through a pager program. 'more-help' is disabled on platforms without a working 'fork(2)' function. The 'PAGER' environment variable is used to select the program, defaulting to 'more'. Both will exit with a status code of 0. gnutls-serv - GnuTLS server Usage: gnutls-serv [ - [] | --[{=| }] ]... -d, --debug=num Enable debugging - it must be in the range: 0 to 9999 --noticket Don't accept session tickets -g, --generate Generate Diffie-Hellman and RSA-export parameters -q, --quiet Suppress some messages --nodb Do not use a resumption database --http Act as an HTTP server --echo Act as an Echo server -u, --udp Use DTLS (datagram TLS) over UDP --mtu=num Set MTU for datagram TLS - it must be in the range: 0 to 17000 --srtp-profiles=str Offer SRTP profiles -a, --disable-client-cert Do not request a client certificate -r, --require-client-cert Require a client certificate -b, --heartbeat Activate heartbeat support --x509fmtder Use DER format for certificates to read from --priority=str Priorities string --dhparams=file DH params file to use - file must pre-exist --x509cafile=str Certificate file or PKCS #11 URL to use --x509crlfile=file CRL file to use - file must pre-exist --pgpkeyfile=file PGP Key file to use - file must pre-exist --pgpkeyring=file PGP Key ring file to use - file must pre-exist --pgpcertfile=file PGP Public Key (certificate) file to use - file must pre-exist --x509keyfile=str X.509 key file or PKCS #11 URL to use --x509certfile=str X.509 Certificate file or PKCS #11 URL to use --x509dsakeyfile=str Alternative X.509 key file or PKCS #11 URL to use --x509dsacertfile=str Alternative X.509 Certificate file or PKCS #11 URL to use --x509ecckeyfile=str Alternative X.509 key file or PKCS #11 URL to use --x509ecccertfile=str Alternative X.509 Certificate file or PKCS #11 URL to use --pgpsubkey=str PGP subkey to use (hex or auto) --srppasswd=file SRP password file to use - file must pre-exist --srppasswdconf=file SRP password configuration file to use - file must pre-exist --pskpasswd=file PSK password file to use - file must pre-exist --pskhint=str PSK identity hint to use --ocsp-response=file The OCSP response to send to client - file must pre-exist -p, --port=num The port to connect to -l, --list Print a list of the supported algorithms and modes -v, --version[=arg] output version information and exit -h, --help display extended usage information and exit -!, --more-help extended usage information passed thru pager Options are specified by doubled hyphens and their name or by a single hyphen and the flag character. Server program that listens to incoming TLS connections. Please send bug reports to: <@PACKAGE_BUGREPORT@> debug option (-d) ----------------- This is the "enable debugging" option. This option takes a number argument. Specifies the debug level. heartbeat option (-b) --------------------- This is the "activate heartbeat support" option. Regularly ping client via heartbeat extension messages priority option --------------- This is the "priorities string" option. This option takes a string argument. TLS algorithms and protocols to enable. You can use predefined sets of ciphersuites such as PERFORMANCE, NORMAL, SECURE128, SECURE256. The default is NORMAL. Check the GnuTLS manual on section "Priority strings" for more information on allowed keywords ocsp-response option -------------------- This is the "the ocsp response to send to client" option. This option takes a file argument. If the client requested an OCSP response, return data from this file to the client. list option (-l) ---------------- This is the "print a list of the supported algorithms and modes" option. Print a list of the supported algorithms and modes. If a priority string is given then only the enabled ciphersuites are shown. gnutls-serv exit status ----------------------- One of the following exit values will be returned: '0 (EXIT_SUCCESS)' Successful program execution. '1 (EXIT_FAILURE)' The operation failed or the command syntax was not valid. gnutls-serv See Also -------------------- gnutls-cli-debug(1), gnutls-cli(1) gnutls-serv Examples -------------------- Running your own TLS server based on GnuTLS can be useful when debugging clients and/or GnuTLS itself. This section describes how to use 'gnutls-serv' as a simple HTTPS server. The most basic server can be started as: gnutls-serv --http --priority "NORMAL:+ANON-ECDH:+ANON-DH" It will only support anonymous ciphersuites, which many TLS clients refuse to use. The next step is to add support for X.509. First we generate a CA: $ certtool --generate-privkey > x509-ca-key.pem $ echo 'cn = GnuTLS test CA' > ca.tmpl $ echo 'ca' >> ca.tmpl $ echo 'cert_signing_key' >> ca.tmpl $ certtool --generate-self-signed --load-privkey x509-ca-key.pem \ --template ca.tmpl --outfile x509-ca.pem ... Then generate a server certificate. Remember to change the dns_name value to the name of your server host, or skip that command to avoid the field. $ certtool --generate-privkey > x509-server-key.pem $ echo 'organization = GnuTLS test server' > server.tmpl $ echo 'cn = test.gnutls.org' >> server.tmpl $ echo 'tls_www_server' >> server.tmpl $ echo 'encryption_key' >> server.tmpl $ echo 'signing_key' >> server.tmpl $ echo 'dns_name = test.gnutls.org' >> server.tmpl $ certtool --generate-certificate --load-privkey x509-server-key.pem \ --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \ --template server.tmpl --outfile x509-server.pem ... For use in the client, you may want to generate a client certificate as well. $ certtool --generate-privkey > x509-client-key.pem $ echo 'cn = GnuTLS test client' > client.tmpl $ echo 'tls_www_client' >> client.tmpl $ echo 'encryption_key' >> client.tmpl $ echo 'signing_key' >> client.tmpl $ certtool --generate-certificate --load-privkey x509-client-key.pem \ --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \ --template client.tmpl --outfile x509-client.pem ... To be able to import the client key/certificate into some applications, you will need to convert them into a PKCS#12 structure. This also encrypts the security sensitive key with a password. $ certtool --to-p12 --load-ca-certificate x509-ca.pem \ --load-privkey x509-client-key.pem --load-certificate x509-client.pem \ --outder --outfile x509-client.p12 For icing, we'll create a proxy certificate for the client too. $ certtool --generate-privkey > x509-proxy-key.pem $ echo 'cn = GnuTLS test client proxy' > proxy.tmpl $ certtool --generate-proxy --load-privkey x509-proxy-key.pem \ --load-ca-certificate x509-client.pem --load-ca-privkey x509-client-key.pem \ --load-certificate x509-client.pem --template proxy.tmpl \ --outfile x509-proxy.pem ... Then start the server again: $ gnutls-serv --http \ --x509cafile x509-ca.pem \ --x509keyfile x509-server-key.pem \ --x509certfile x509-server.pem Try connecting to the server using your web browser. Note that the server listens to port 5556 by default. While you are at it, to allow connections using DSA, you can also create a DSA key and certificate for the server. These credentials will be used in the final example below. $ certtool --generate-privkey --dsa > x509-server-key-dsa.pem $ certtool --generate-certificate --load-privkey x509-server-key-dsa.pem \ --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \ --template server.tmpl --outfile x509-server-dsa.pem ... The next step is to create OpenPGP credentials for the server. gpg --gen-key ...enter whatever details you want, use 'test.gnutls.org' as name... Make a note of the OpenPGP key identifier of the newly generated key, here it was '5D1D14D8'. You will need to export the key for GnuTLS to be able to use it. gpg -a --export 5D1D14D8 > openpgp-server.txt gpg --export 5D1D14D8 > openpgp-server.bin gpg --export-secret-keys 5D1D14D8 > openpgp-server-key.bin gpg -a --export-secret-keys 5D1D14D8 > openpgp-server-key.txt Let's start the server with support for OpenPGP credentials: gnutls-serv --http --priority NORMAL:+CTYPE-OPENPGP \ --pgpkeyfile openpgp-server-key.txt \ --pgpcertfile openpgp-server.txt The next step is to add support for SRP authentication. This requires an SRP password file created with 'srptool'. To start the server with SRP support: gnutls-serv --http --priority NORMAL:+SRP-RSA:+SRP \ --srppasswdconf srp-tpasswd.conf \ --srppasswd srp-passwd.txt Let's also start a server with support for PSK. This would require a password file created with 'psktool'. gnutls-serv --http --priority NORMAL:+ECDHE-PSK:+PSK \ --pskpasswd psk-passwd.txt Finally, we start the server with all the earlier parameters and you get this command: gnutls-serv --http --priority NORMAL:+PSK:+SRP:+CTYPE-OPENPGP \ --x509cafile x509-ca.pem \ --x509keyfile x509-server-key.pem \ --x509certfile x509-server.pem \ --x509dsakeyfile x509-server-key-dsa.pem \ --x509dsacertfile x509-server-dsa.pem \ --pgpkeyfile openpgp-server-key.txt \ --pgpcertfile openpgp-server.txt \ --srppasswdconf srp-tpasswd.conf \ --srppasswd srp-passwd.txt \ --pskpasswd psk-passwd.txt  File: gnutls.info, Node: gnutls-cli-debug Invocation, Prev: gnutls-serv Invocation, Up: Other included programs 9.3 Invoking gnutls-cli-debug ============================= TLS debug client. It sets up multiple TLS connections to a server and queries its capabilities. It was created to assist in debugging GnuTLS, but it might be useful to extract a TLS server's capabilities. It connects to a TLS server, performs tests and print the server's capabilities. If called with the '-v' parameter more checks will be performed. Can be used to check for servers with special needs or bugs. This section was generated by *AutoGen*, using the 'agtexi-cmd' template and the option descriptions for the 'gnutls-cli-debug' program. This software is released under the GNU General Public License, version 3 or later. gnutls-cli-debug help/usage ('--help') -------------------------------------- This is the automatically generated usage text for gnutls-cli-debug. The text printed is the same whether selected with the 'help' option ('--help') or the 'more-help' option ('--more-help'). 'more-help' will print the usage text by passing it through a pager program. 'more-help' is disabled on platforms without a working 'fork(2)' function. The 'PAGER' environment variable is used to select the program, defaulting to 'more'. Both will exit with a status code of 0. gnutls-cli-debug - GnuTLS debug client Usage: gnutls-cli-debug [ - [] | --[{=| }] ]... -d, --debug=num Enable debugging - it must be in the range: 0 to 9999 -V, --verbose More verbose output - may appear multiple times -p, --port=num The port to connect to - it must be in the range: 0 to 65536 -v, --version[=arg] output version information and exit -h, --help display extended usage information and exit -!, --more-help extended usage information passed thru pager Options are specified by doubled hyphens and their name or by a single hyphen and the flag character. Operands and options may be intermixed. They will be reordered. TLS debug client. It sets up multiple TLS connections to a server and queries its capabilities. It was created to assist in debugging GnuTLS, but it might be useful to extract a TLS server's capabilities. It connects to a TLS server, performs tests and print the server's capabilities. If called with the `-v' parameter more checks will be performed. Can be used to check for servers with special needs or bugs. Please send bug reports to: <@PACKAGE_BUGREPORT@> debug option (-d) ----------------- This is the "enable debugging" option. This option takes a number argument. Specifies the debug level. gnutls-cli-debug exit status ---------------------------- One of the following exit values will be returned: '0 (EXIT_SUCCESS)' Successful program execution. '1 (EXIT_FAILURE)' The operation failed or the command syntax was not valid. gnutls-cli-debug See Also ------------------------- gnutls-cli(1), gnutls-serv(1) gnutls-cli-debug Examples ------------------------- $ ../src/gnutls-cli-debug localhost Resolving 'localhost'... Connecting to '127.0.0.1:443'... Checking for SSL 3.0 support... yes Checking whether %COMPAT is required... no Checking for TLS 1.0 support... yes Checking for TLS 1.1 support... no Checking fallback from TLS 1.1 to... TLS 1.0 Checking for TLS 1.2 support... no Checking whether we need to disable TLS 1.0... N/A Checking for Safe renegotiation support... yes Checking for Safe renegotiation support (SCSV)... yes Checking for HTTPS server name... not checked Checking for version rollback bug in RSA PMS... no Checking for version rollback bug in Client Hello... no Checking whether the server ignores the RSA PMS version... no Checking whether the server can accept Hello Extensions... yes Checking whether the server can accept small records (512 bytes)... yes Checking whether the server can accept cipher suites not in SSL 3.0 spec... yes Checking whether the server can accept a bogus TLS record version in the client hello... yes Checking for certificate information... N/A Checking for trusted CAs... N/A Checking whether the server understands TLS closure alerts... partially Checking whether the server supports session resumption... yes Checking for export-grade ciphersuite support... no Checking RSA-export ciphersuite info... N/A Checking for anonymous authentication support... no Checking anonymous Diffie-Hellman group info... N/A Checking for ephemeral Diffie-Hellman support... no Checking ephemeral Diffie-Hellman group info... N/A Checking for ephemeral EC Diffie-Hellman support... yes Checking ephemeral EC Diffie-Hellman group info... Curve SECP256R1 Checking for AES-GCM cipher support... no Checking for AES-CBC cipher support... yes Checking for CAMELLIA cipher support... no Checking for 3DES-CBC cipher support... yes Checking for ARCFOUR 128 cipher support... yes Checking for ARCFOUR 40 cipher support... no Checking for MD5 MAC support... yes Checking for SHA1 MAC support... yes Checking for SHA256 MAC support... no Checking for ZLIB compression support... no Checking for max record size... no Checking for OpenPGP authentication support... no  File: gnutls.info, Node: Internal architecture of GnuTLS, Next: Upgrading from previous versions, Prev: Other included programs, Up: Top 10 Internal Architecture of GnuTLS ********************************** This chapter is to give a brief description of the way GnuTLS works. The focus is to give an idea to potential developers and those who want to know what happens inside the black box. * Menu: * The TLS Protocol:: * TLS Handshake Protocol:: * TLS Authentication Methods:: * TLS Extension Handling:: * Cryptographic Backend::  File: gnutls.info, Node: The TLS Protocol, Next: TLS Handshake Protocol, Up: Internal architecture of GnuTLS 10.1 The TLS Protocol ===================== The main use case for the TLS protocol is shown in *note Figure 10.1: fig-client-server. A user of a library implementing the protocol expects no less than this functionality, i.e., to be able to set parameters such as the accepted security level, perform a negotiation with the peer and be able to exchange data. [image src="gnutls-client-server-use-case.png"] Figure 10.1: TLS protocol use case.  File: gnutls.info, Node: TLS Handshake Protocol, Next: TLS Authentication Methods, Prev: The TLS Protocol, Up: Internal architecture of GnuTLS 10.2 TLS Handshake Protocol =========================== The GnuTLS handshake protocol is implemented as a state machine that waits for input or returns immediately when the non-blocking transport layer functions are used. The main idea is shown in *note Figure 10.2: fig-gnutls-handshake. [image src="gnutls-handshake-state.png"] Figure 10.2: GnuTLS handshake state machine. Also the way the input is processed varies per ciphersuite. Several implementations of the internal handlers are available and *note gnutls_handshake:: only multiplexes the input to the appropriate handler. For example a PSK ciphersuite has a different implementation of the 'process_client_key_exchange' than a certificate ciphersuite. We illustrate the idea in *note Figure 10.3: fig-gnutls-handshake-sequence. [image src="gnutls-handshake-sequence.png"] Figure 10.3: GnuTLS handshake process sequence.  File: gnutls.info, Node: TLS Authentication Methods, Next: TLS Extension Handling, Prev: TLS Handshake Protocol, Up: Internal architecture of GnuTLS 10.3 TLS Authentication Methods =============================== In GnuTLS authentication methods can be implemented quite easily. Since the required changes to add a new authentication method affect only the handshake protocol, a simple interface is used. An authentication method needs to implement the functions shown below. typedef struct { const char *name; int (*gnutls_generate_server_certificate) (gnutls_session_t, gnutls_buffer_st*); int (*gnutls_generate_client_certificate) (gnutls_session_t, gnutls_buffer_st*); int (*gnutls_generate_server_kx) (gnutls_session_t, gnutls_buffer_st*); int (*gnutls_generate_client_kx) (gnutls_session_t, gnutls_buffer_st*); int (*gnutls_generate_client_cert_vrfy) (gnutls_session_t, gnutls_buffer_st *); int (*gnutls_generate_server_certificate_request) (gnutls_session_t, gnutls_buffer_st *); int (*gnutls_process_server_certificate) (gnutls_session_t, opaque *, size_t); int (*gnutls_process_client_certificate) (gnutls_session_t, opaque *, size_t); int (*gnutls_process_server_kx) (gnutls_session_t, opaque *, size_t); int (*gnutls_process_client_kx) (gnutls_session_t, opaque *, size_t); int (*gnutls_process_client_cert_vrfy) (gnutls_session_t, opaque *, size_t); int (*gnutls_process_server_certificate_request) (gnutls_session_t, opaque *, size_t); } mod_auth_st; Those functions are responsible for the interpretation of the handshake protocol messages. It is common for such functions to read data from one or more 'credentials_t' structures(1) and write data, such as certificates, usernames etc. to 'auth_info_t' structures. Simple examples of existing authentication methods can be seen in 'auth/psk.c' for PSK ciphersuites and 'auth/srp.c' for SRP ciphersuites. After implementing these functions the structure holding its pointers has to be registered in 'gnutls_algorithms.c' in the '_gnutls_kx_algorithms' structure. ---------- Footnotes ---------- (1) such as the 'gnutls_certificate_credentials_t' structures  File: gnutls.info, Node: TLS Extension Handling, Next: Cryptographic Backend, Prev: TLS Authentication Methods, Up: Internal architecture of GnuTLS 10.4 TLS Extension Handling =========================== As with authentication methods, the TLS extensions handlers can be implemented using the interface shown below. typedef int (*gnutls_ext_recv_func) (gnutls_session_t session, const unsigned char *data, size_t len); typedef int (*gnutls_ext_send_func) (gnutls_session_t session, gnutls_buffer_st *extdata); Here there are two functions, one for receiving the extension data and one for sending. These functions have to check internally whether they operate in client or server side. A simple example of an extension handler can be seen in 'ext/srp.c' in GnuTLS' source code. After implementing these functions, together with the extension number they handle, they have to be registered using '_gnutls_ext_register' in 'gnutls_extensions.c' typically within '_gnutls_ext_init'. Adding a new TLS extension -------------------------- Adding support for a new TLS extension is done from time to time, and the process to do so is not difficult. Here are the steps you need to follow if you wish to do this yourself. For sake of discussion, let's consider adding support for the hypothetical TLS extension 'foobar'. Add 'configure' option like '--enable-foobar' or '--disable-foobar'. .................................................................... This step is useful when the extension code is large and it might be desirable to disable the extension under some circumstances. Otherwise it can be safely skipped. Whether to chose enable or disable depends on whether you intend to make the extension be enabled by default. Look at existing checks (i.e., SRP, authz) for how to model the code. For example: AC_MSG_CHECKING([whether to disable foobar support]) AC_ARG_ENABLE(foobar, AS_HELP_STRING([--disable-foobar], [disable foobar support]), ac_enable_foobar=no) if test x$ac_enable_foobar != xno; then AC_MSG_RESULT(no) AC_DEFINE(ENABLE_FOOBAR, 1, [enable foobar]) else ac_full=0 AC_MSG_RESULT(yes) fi AM_CONDITIONAL(ENABLE_FOOBAR, test "$ac_enable_foobar" != "no") These lines should go in 'm4/hooks.m4'. Add IANA extension value to 'extensions_t' in 'gnutls_int.h'. ............................................................. A good name for the value would be GNUTLS_EXTENSION_FOOBAR. Check with for allocated values. For experiments, you could pick a number but remember that some consider it a bad idea to deploy such modified version since it will lead to interoperability problems in the future when the IANA allocates that number to someone else, or when the foobar protocol is allocated another number. Add an entry to '_gnutls_extensions' in 'gnutls_extensions.c'. .............................................................. A typical entry would be: int ret; #if ENABLE_FOOBAR ret = _gnutls_ext_register (&foobar_ext); if (ret != GNUTLS_E_SUCCESS) return ret; #endif Most likely you'll need to add an '#include "ext/foobar.h"', that will contain something like like: extension_entry_st foobar_ext = { .name = "FOOBAR", .type = GNUTLS_EXTENSION_FOOBAR, .parse_type = GNUTLS_EXT_TLS, .recv_func = _foobar_recv_params, .send_func = _foobar_send_params, .pack_func = _foobar_pack, .unpack_func = _foobar_unpack, .deinit_func = NULL } The GNUTLS_EXTENSION_FOOBAR is the integer value you added to 'gnutls_int.h' earlier. In this structure you specify the functions to read the extension from the hello message, the function to send the reply to, and two more functions to pack and unpack from stored session data (e.g. when resumming a session). The 'deinit' function will be called to deinitialize the extension's private parameters, if any. Note that the conditional 'ENABLE_FOOBAR' definition should only be used if step 1 with the 'configure' options has taken place. Add new files that implement the extension. ........................................... The functions you are responsible to add are those mentioned in the previous step. They should be added in a file such as 'ext/foobar.c' and headers should be placed in 'ext/foobar.h'. As a starter, you could add this: int _foobar_recv_params (gnutls_session_t session, const opaque * data, size_t data_size) { return 0; } int _foobar_send_params (gnutls_session_t session, gnutls_buffer_st* data) { return 0; } int _foobar_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps) { /* Append the extension's internal state to buffer */ return 0; } int _foobar_unpack (gnutls_buffer_st * ps, extension_priv_data_t * epriv) { /* Read the internal state from buffer */ return 0; } The '_foobar_recv_params' function is responsible for parsing incoming extension data (both in the client and server). The '_foobar_send_params' function is responsible for sending extension data (both in the client and server). If you receive length fields that don't match, return 'GNUTLS_E_UNEXPECTED_PACKET_LENGTH'. If you receive invalid data, return 'GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER'. You can use other error codes from the list in *note Error codes::. Return 0 on success. An extension typically stores private information in the 'session' data for later usage. That can be done using the functions '_gnutls_ext_set_session_data' and '_gnutls_ext_get_session_data'. You can check simple examples at 'ext/max_record.c' and 'ext/server_name.c' extensions. That private information can be saved and restored across session resumption if the following functions are set: The '_foobar_pack' function is responsible for packing internal extension data to save them in the session resumption storage. The '_foobar_unpack' function is responsible for restoring session data from the session resumption storage. Recall that both the client and server, send and receive parameters, and your code most likely will need to do different things depending on which mode it is in. It may be useful to make this distinction explicit in the code. Thus, for example, a better template than above would be: int _gnutls_foobar_recv_params (gnutls_session_t session, const opaque * data, size_t data_size) { if (session->security_parameters.entity == GNUTLS_CLIENT) return foobar_recv_client (session, data, data_size); else return foobar_recv_server (session, data, data_size); } int _gnutls_foobar_send_params (gnutls_session_t session, gnutls_buffer_st * data) { if (session->security_parameters.entity == GNUTLS_CLIENT) return foobar_send_client (session, data); else return foobar_send_server (session, data); } The functions used would be declared as 'static' functions, of the appropriate prototype, in the same file. When adding the files, you'll need to add them to 'ext/Makefile.am' as well, for example: if ENABLE_FOOBAR libgnutls_ext_la_SOURCES += ext/foobar.c ext/foobar.h endif Add API functions to enable/disable the extension. .................................................. It might be desirable to allow users of the extension to request use of the extension, or set extension specific data. This can be implemented by adding extension specific function calls that can be added to 'includes/gnutls/gnutls.h', as long as the LGPLv2.1+ applies. The implementation of the function should lie in the 'ext/foobar.c' file. To make the API available in the shared library you need to add the symbol in 'lib/libgnutls.map', so that the symbol is exported properly. When writing GTK-DOC style documentation for your new APIs, don't forget to add 'Since:' tags to indicate the GnuTLS version the API was introduced in. Adding a new Supplemental Data Handshake Message ------------------------------------------------ TLS handshake extensions allow to send so called supplemental data handshake messages [_RFC4680_]. This short section explains how to implement a supplemental data handshake message for a given TLS extension. First of all, modify your extension 'foobar' in the way, the that flags 'session->security_parameters.do_send_supplemental' and 'session->security_parameters.do_recv_supplemental' are set: int _gnutls_foobar_recv_params (gnutls_session_t session, const opaque * data, size_t _data_size) { ... session->security_parameters.do_recv_supplemental=1; ... } int _gnutls_foobar_send_params (gnutls_session_t session, gnutls_buffer_st *extdata) { ... session->security_parameters.do_send_supplemental=1; ... } Furthermore add the functions '_foobar_supp_recv_params' and '_foobar_supp_send_params' to '_foobar.h' and '_foobar.c'. The following example code shows how to send a "Hello World" string in the supplemental data handshake message: int _foobar_supp_recv_params(gnutls_session_t session, const opaque *data, size_t _data_size) { uint8_t len = _data_size; unsigned char *msg; msg = gnutls_malloc(len); if (msg == NULL) return GNUTLS_E_MEMORY_ERROR; memcpy(msg, data, len); msg[len]='\0'; /* do something with msg */ gnutls_free(msg); return len; } int _foobar_supp_send_params(gnutls_session_t session, gnutls_buffer_st *buf) { unsigned char *msg = "hello world"; int len = strlen(msg); _gnutls_buffer_append_data_prefix(buf, 8, msg, len); return len; } Afterwards, add the new supplemental data handshake message to 'lib/gnutls_supplemental.c' by adding a new entry to the '_gnutls_supplemental[]' structure: gnutls_supplemental_entry _gnutls_supplemental[] = { {"foobar", GNUTLS_SUPPLEMENTAL_FOOBAR_DATA, _foobar_supp_recv_params, _foobar_supp_send_params}, {0, 0, 0, 0} }; You have to include your 'foobar.h' header file as well: #include "foobar.h" Lastly, add the new supplemental data type to 'lib/includes/gnutls/gnutls.h': typedef enum { GNUTLS_SUPPLEMENTAL_USER_MAPPING_DATA = 0, GNUTLS_SUPPLEMENTAL_FOOBAR_DATA = 1 } gnutls_supplemental_data_format_type_t; Heartbeat extension. .................... One such extension is HeartBeat protocol (RFC6520: ) implementation. To enable it use option -heartbeat with example client and server supplied with gnutls: ./doc/credentials/gnutls-http-serv --priority "NORMAL:-CIPHER-ALL:+NULL" -d 100 \ --heartbeat --echo ./src/gnutls-cli --priority "NORMAL:-CIPHER-ALL:+NULL" -d 100 localhost -p 5556 \ --insecure --heartbeat After that pasting **HEARTBEAT** command into gnutls-cli will trigger corresponding command on the server and it will send HeartBeat Request with random length to client. Another way is to run capabilities check with: ./doc/credentials/gnutls-http-serv -d 100 --heartbeat ./src/gnutls-cli-debug localhost -p 5556  File: gnutls.info, Node: Cryptographic Backend, Prev: TLS Extension Handling, Up: Internal architecture of GnuTLS 10.5 Cryptographic Backend ========================== Today most new processors, either for embedded or desktop systems include either instructions intended to speed up cryptographic operations, or a co-processor with cryptographic capabilities. Taking advantage of those is a challenging task for every cryptographic application or library. Unfortunately the cryptographic library that GnuTLS is based on takes no advantage of these capabilities. For this reason GnuTLS handles this internally by following a layered approach to accessing cryptographic operations as in *note Figure 10.4: fig-crypto-layers. [image src="gnutls-crypto-layers.png"] Figure 10.4: GnuTLS cryptographic back-end design. The TLS layer uses a cryptographic provider layer, that will in turn either use the default crypto provider - a software crypto library, or use an external crypto provider, if available in the local system. The reason of handling the external cryptographic provider in GnuTLS and not delegating it to the cryptographic libraries, is that none of the supported cryptographic libraries support '/dev/crypto' or CPU-optimized cryptography in an efficient way. Cryptographic library layer --------------------------- The Cryptographic library layer, currently supports only libnettle. Older versions of GnuTLS used to support libgcrypt, but it was switched with nettle mainly for performance reasons(1) and secondary because it is a simpler library to use. In the future other cryptographic libraries might be supported as well. External cryptography provider ------------------------------ Systems that include a cryptographic co-processor, typically come with kernel drivers to utilize the operations from software. For this reason GnuTLS provides a layer where each individual algorithm used can be replaced by another implementation, i.e., the one provided by the driver. The FreeBSD, OpenBSD and Linux kernels(2) include already a number of hardware assisted implementations, and also provide an interface to access them, called '/dev/crypto'. GnuTLS will take advantage of this interface if compiled with special options. That is because in most systems where hardware-assisted cryptographic operations are not available, using this interface might actually harm performance. In systems that include cryptographic instructions with the CPU's instructions set, using the kernel interface will introduce an unneeded layer. For this reason GnuTLS includes such optimizations found in popular processors such as the AES-NI or VIA PADLOCK instruction sets. This is achieved using a mechanism that detects CPU capabilities and overrides parts of crypto back-end at runtime. The next section discusses the registration of a detected algorithm optimization. For more information please consult the GnuTLS source code in 'lib/accelerated/'. Overriding specific algorithms .............................. When an optimized implementation of a single algorithm is available, say a hardware assisted version of AES-CBC then the following (internal) functions, from 'crypto-backend.h', can be used to register those algorithms. * 'gnutls_crypto_single_cipher_register': To register a cipher algorithm. * 'gnutls_crypto_single_digest_register': To register a hash (digest) or MAC algorithm. Those registration functions will only replace the specified algorithm and leave the rest of subsystem intact. Overriding the cryptographic library .................................... In some systems, that might contain a broad acceleration engine, it might be desirable to override big parts of the cryptographic back-end, or even all of them. The following functions are provided for this reason. * 'gnutls_crypto_cipher_register': To override the cryptographic algorithms back-end. * 'gnutls_crypto_digest_register': To override the digest algorithms back-end. * 'gnutls_crypto_rnd_register': To override the random number generator back-end. * 'gnutls_crypto_bigint_register': To override the big number number operations back-end. * 'gnutls_crypto_pk_register': To override the public key encryption back-end. This is tied to the big number operations so either none or both of them should be overridden. ---------- Footnotes ---------- (1) See . (2) Check for the Linux kernel implementation of '/dev/crypto'.  File: gnutls.info, Node: Upgrading from previous versions, Next: Support, Prev: Internal architecture of GnuTLS, Up: Top Appendix A Upgrading from previous versions ******************************************* The GnuTLS library typically maintains binary and source code compatibility across versions. The releases that have the major version increased break binary compatibility but source compatibility is provided. This section lists exceptional cases where changes to existing code are required due to library changes. Upgrading to 2.12.x from previous versions ========================================== GnuTLS 2.12.x is binary compatible with previous versions but changes the semantics of 'gnutls_transport_set_lowat', which might cause breakage in applications that relied on its default value be 1. Two fixes are proposed: * Quick fix. Explicitly call 'gnutls_transport_set_lowat (session, 1);' after *note gnutls_init::. * Long term fix. Because later versions of gnutls abolish the functionality of using the system call 'select' to check for gnutls pending data, the function *note gnutls_record_check_pending:: has to be used to achieve the same functionality as described in *note Asynchronous operation::. Upgrading to 3.0.x from 2.12.x ============================== GnuTLS 3.0.x is source compatible with previous versions except for the functions listed below. Old function Replacement ------------------------------------------------------------------- 'gnutls_transport_set_lowat'To replace its functionality the function *note gnutls_record_check_pending:: has to be used, as described in *note Asynchronous operation:: 'gnutls_session_get_server_random',They are replaced by the safer function 'gnutls_session_get_client_random'*note gnutls_session_get_random:: 'gnutls_session_get_master_secret'Replaced by the keying material exporters discussed in *note Deriving keys for other applications/protocols:: 'gnutls_transport_set_global_errno'Replaced by using the system's errno fascility or *note gnutls_transport_set_errno::. 'gnutls_x509_privkey_verify_data'Replaced by *note gnutls_pubkey_verify_data::. 'gnutls_certificate_verify_peers'Replaced by *note gnutls_certificate_verify_peers2::. 'gnutls_psk_netconf_derive_key'Removed. The key derivation function was never standardized. 'gnutls_session_set_finished_function'Removed. 'gnutls_ext_register' Removed. Extension registration API is now internal to allow easier changes in the API. 'gnutls_certificate_get_x509_crls',Removed to allow updating the internal 'gnutls_certificate_get_x509_cas'structures. Replaced by *note gnutls_certificate_get_issuer::. 'gnutls_certificate_get_openpgp_keyring'Removed. 'gnutls_ia_*' Removed. The inner application extensions were completely removed (they failed to be standardized). Upgrading to 3.1.x from 3.0.x ============================= GnuTLS 3.1.x is source and binary compatible with GnuTLS 3.0.x releases. Few functions have been deprecated and are listed below. Old function Replacement ------------------------------------------------------------------- 'gnutls_pubkey_verify_hash'The function *note gnutls_pubkey_verify_hash2:: is provided and is functionally equivalent and safer to use. 'gnutls_pubkey_verify_data'The function *note gnutls_pubkey_verify_data2:: is provided and is functionally equivalent and safer to use. Upgrading to 3.2.x from 3.1.x ============================= GnuTLS 3.2.x is source and binary compatible with GnuTLS 3.1.x releases. Few functions have been deprecated and are listed below. Old function Replacement ------------------------------------------------------------------- 'gnutls_privkey_sign_raw_data'The function *note gnutls_privkey_sign_hash:: is equivalent when the flag 'GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA' is specified.  File: gnutls.info, Node: Support, Next: Error codes, Prev: Upgrading from previous versions, Up: Top Appendix B Support ****************** * Menu: * Getting help:: * Commercial Support:: * Bug Reports:: * Contributing:: * Certification::  File: gnutls.info, Node: Getting help, Next: Commercial Support, Up: Support B.1 Getting Help ================ A mailing list where users may help each other exists, and you can reach it by sending e-mail to . Archives of the mailing list discussions, and an interface to manage subscriptions, is available through the World Wide Web at . A mailing list for developers are also available, see . Bug reports should be sent to , see *note Bug Reports::.  File: gnutls.info, Node: Commercial Support, Next: Bug Reports, Prev: Getting help, Up: Support B.2 Commercial Support ====================== Commercial support is available for users of GnuTLS. The kind of support that can be purchased may include: * Implement new features. Such as a new TLS extension. * Port GnuTLS to new platforms. This could include porting to an embedded platforms that may need memory or size optimization. * Integrating TLS as a security environment in your existing project. * System design of components related to TLS. If you are interested, please write to: Simon Josefsson Datakonsult Hagagatan 24 113 47 Stockholm Sweden E-mail: simon@josefsson.org If your company provides support related to GnuTLS and would like to be mentioned here, contact the authors.  File: gnutls.info, Node: Bug Reports, Next: Contributing, Prev: Commercial Support, Up: Support B.3 Bug Reports =============== If you think you have found a bug in GnuTLS, please investigate it and report it. * Please make sure that the bug is really in GnuTLS, and preferably also check that it hasn't already been fixed in the latest version. * You have to send us a test case that makes it possible for us to reproduce the bug. * You also have to explain what is wrong; if you get a crash, or if the results printed are not good and in that case, in what way. Make sure that the bug report includes all information you would need to fix this kind of bug for someone else. Please make an effort to produce a self-contained report, with something definite that can be tested or debugged. Vague queries or piecemeal messages are difficult to act on and don't help the development effort. If your bug report is good, we will do our best to help you to get a corrected version of the software; if the bug report is poor, we won't do anything about it (apart from asking you to send better bug reports). If you think something in this manual is unclear, or downright incorrect, or if the language needs to be improved, please also send a note. Send your bug report to: 'bugs@gnutls.org'  File: gnutls.info, Node: Contributing, Next: Certification, Prev: Bug Reports, Up: Support B.4 Contributing ================ If you want to submit a patch for inclusion - from solving a typo you discovered, up to adding support for a new feature - you should submit it as a bug report, using the process in *note Bug Reports::. There are some things that you can do to increase the chances for it to be included in the official package. Unless your patch is very small (say, under 10 lines) we require that you assign the copyright of your work to the Free Software Foundation. This is to protect the freedom of the project. If you have not already signed papers, we will send you the necessary information when you submit your contribution. For contributions that doesn't consist of actual programming code, the only guidelines are common sense. For code contributions, a number of style guides will help you: * Coding Style. Follow the GNU Standards document. If you normally code using another coding standard, there is no problem, but you should use 'indent' to reformat the code before submitting your work. * Use the unified diff format 'diff -u'. * Return errors. No reason whatsoever should abort the execution of the library. Even memory allocation errors, e.g. when malloc return NULL, should work although result in an error code. * Design with thread safety in mind. Don't use global variables. Don't even write to per-handle global variables unless the documented behaviour of the function you write is to write to the per-handle global variable. * Avoid using the C math library. It causes problems for embedded implementations, and in most situations it is very easy to avoid using it. * Document your functions. Use comments before each function headers, that, if properly formatted, are extracted into Texinfo manuals and GTK-DOC web pages. * Supply a ChangeLog and NEWS entries, where appropriate.  File: gnutls.info, Node: Certification, Prev: Contributing, Up: Support B.5 Certification ================= Many cryptographic libraries claim certifications from national or international bodies. These certifications are tied on a specific (and often restricted) version of the library or a specific product using the library, and typically in the case of software they assure that the algorithms implemented are correct. The major certifications known are: * USA's FIPS 140-2 at Level 1 which certifies that approved algorithms are used (see ); * Common Criteria for Information Technology Security Evaluation (CC), an international standard for verification of elaborate security claims (see ). Obtaining such a certification is an expensive and elaborate job that has no immediate value for a continuously developed free software library (as the certification is tied to the particular version tested), and in the case of algorithm verification of FIPS 140-2 it doesn't make much sense as the library is freely available and anyone can verify the correctness of algorithm implementation. As such we are not actively pursuing this kind of certification. If you are, nevertheless, interested, see *note Commercial Support::.  File: gnutls.info, Node: Error codes, Next: Supported ciphersuites, Prev: Support, Up: Top Appendix C Error Codes and Descriptions *************************************** The error codes used throughout the library are described below. The return code 'GNUTLS_E_SUCCESS' indicate successful operation, and is guaranteed to have the value 0, so you can use it in logical expressions. 0 GNUTLS_E_SUCCESS Success. -3 GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHMCould not negotiate a supported compression method. -6 GNUTLS_E_UNKNOWN_CIPHER_TYPE The cipher type is unsupported. -7 GNUTLS_E_LARGE_PACKET The transmitted packet is too large (EMSGSIZE). -8 GNUTLS_E_UNSUPPORTED_VERSION_PACKETA record packet with illegal version was received. -9 GNUTLS_E_UNEXPECTED_PACKET_LENGTHA TLS packet with unexpected length was received. -10 GNUTLS_E_INVALID_SESSION The specified session has been invalidated for some reason. -12 GNUTLS_E_FATAL_ALERT_RECEIVED A TLS fatal alert has been received. -15 GNUTLS_E_UNEXPECTED_PACKET An unexpected TLS packet was received. -16 GNUTLS_E_WARNING_ALERT_RECEIVEDA TLS warning alert has been received. -18 GNUTLS_E_ERROR_IN_FINISHED_PACKETAn error was encountered at the TLS Finished packet calculation. -19 GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKETAn unexpected TLS handshake packet was received. -21 GNUTLS_E_UNKNOWN_CIPHER_SUITE Could not negotiate a supported cipher suite. -22 GNUTLS_E_UNWANTED_ALGORITHM An algorithm that is not enabled was negotiated. -23 GNUTLS_E_MPI_SCAN_FAILED The scanning of a large integer has failed. -24 GNUTLS_E_DECRYPTION_FAILED Decryption has failed. -25 GNUTLS_E_MEMORY_ERROR Internal error in memory allocation. -26 GNUTLS_E_DECOMPRESSION_FAILED Decompression of the TLS record packet has failed. -27 GNUTLS_E_COMPRESSION_FAILED Compression of the TLS record packet has failed. -28 GNUTLS_E_AGAIN Resource temporarily unavailable, try again. -29 GNUTLS_E_EXPIRED The requested session has expired. -30 GNUTLS_E_DB_ERROR Error in Database backend. -31 GNUTLS_E_SRP_PWD_ERROR Error in password file. -32 GNUTLS_E_INSUFFICIENT_CREDENTIALSInsufficient credentials for that request. -33 GNUTLS_E_HASH_FAILED Hashing has failed. -34 GNUTLS_E_BASE64_DECODING_ERRORBase64 decoding error. -35 GNUTLS_E_MPI_PRINT_FAILED Could not export a large integer. -37 GNUTLS_E_REHANDSHAKE Rehandshake was requested by the peer. -38 GNUTLS_E_GOT_APPLICATION_DATA TLS Application data were received, while expecting handshake data. -39 GNUTLS_E_RECORD_LIMIT_REACHED The upper limit of record packet sequence numbers has been reached. Wow! -40 GNUTLS_E_ENCRYPTION_FAILED Encryption has failed. -43 GNUTLS_E_CERTIFICATE_ERROR Error in the certificate. -44 GNUTLS_E_PK_ENCRYPTION_FAILED Public key encryption has failed. -45 GNUTLS_E_PK_DECRYPTION_FAILED Public key decryption has failed. -46 GNUTLS_E_PK_SIGN_FAILED Public key signing has failed. -47 GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSIONUnsupported critical extension in X.509 certificate. -48 GNUTLS_E_KEY_USAGE_VIOLATION Key usage violation in certificate has been detected. -49 GNUTLS_E_NO_CERTIFICATE_FOUND No certificate was found. -50 GNUTLS_E_INVALID_REQUEST The request is invalid. -51 GNUTLS_E_SHORT_MEMORY_BUFFER The given memory buffer is too short to hold parameters. -52 GNUTLS_E_INTERRUPTED Function was interrupted. -53 GNUTLS_E_PUSH_ERROR Error in the push function. -54 GNUTLS_E_PULL_ERROR Error in the pull function. -55 GNUTLS_E_RECEIVED_ILLEGAL_PARAMETERAn illegal parameter has been received. -56 GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLEThe requested data were not available. -57 GNUTLS_E_PKCS1_WRONG_PAD Wrong padding in PKCS1 packet. -58 GNUTLS_E_RECEIVED_ILLEGAL_EXTENSIONAn illegal TLS extension was received. -59 GNUTLS_E_INTERNAL_ERROR GnuTLS internal error. -60 GNUTLS_E_CERTIFICATE_KEY_MISMATCHThe certificate and the given key do not match. -61 GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPEThe certificate type is not supported. -62 GNUTLS_E_X509_UNKNOWN_SAN Unknown Subject Alternative name in X.509 certificate. -63 GNUTLS_E_DH_PRIME_UNACCEPTABLEThe Diffie-Hellman prime sent by the server is not acceptable (not long enough). -64 GNUTLS_E_FILE_ERROR Error while reading file. -67 GNUTLS_E_ASN1_ELEMENT_NOT_FOUNDASN1 parser: Element was not found. -68 GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUNDASN1 parser: Identifier was not found -69 GNUTLS_E_ASN1_DER_ERROR ASN1 parser: Error in DER parsing. -70 GNUTLS_E_ASN1_VALUE_NOT_FOUND ASN1 parser: Value was not found. -71 GNUTLS_E_ASN1_GENERIC_ERROR ASN1 parser: Generic parsing error. -72 GNUTLS_E_ASN1_VALUE_NOT_VALID ASN1 parser: Value is not valid. -73 GNUTLS_E_ASN1_TAG_ERROR ASN1 parser: Error in TAG. -74 GNUTLS_E_ASN1_TAG_IMPLICIT ASN1 parser: error in implicit tag -75 GNUTLS_E_ASN1_TYPE_ANY_ERROR ASN1 parser: Error in type 'ANY'. -76 GNUTLS_E_ASN1_SYNTAX_ERROR ASN1 parser: Syntax error. -77 GNUTLS_E_ASN1_DER_OVERFLOW ASN1 parser: Overflow in DER parsing. -78 GNUTLS_E_TOO_MANY_EMPTY_PACKETSToo many empty record packets have been received. -79 GNUTLS_E_OPENPGP_UID_REVOKED The OpenPGP User ID is revoked. -80 GNUTLS_E_UNKNOWN_PK_ALGORITHM An unknown public key algorithm was encountered. -81 GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETSToo many handshake packets have been received. -84 GNUTLS_E_NO_TEMPORARY_RSA_PARAMSNo temporary RSA parameters were found. -86 GNUTLS_E_NO_COMPRESSION_ALGORITHMSNo supported compression algorithms have been found. -87 GNUTLS_E_NO_CIPHER_SUITES No supported cipher suites have been found. -88 GNUTLS_E_OPENPGP_GETKEY_FAILEDCould not get OpenPGP key. -89 GNUTLS_E_PK_SIG_VERIFY_FAILED Public key signature verification has failed. -90 GNUTLS_E_ILLEGAL_SRP_USERNAME The SRP username supplied is illegal. -91 GNUTLS_E_SRP_PWD_PARSING_ERRORParsing error in password file. -93 GNUTLS_E_NO_TEMPORARY_DH_PARAMSNo temporary DH parameters were found. -94 GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTEDThe OpenPGP fingerprint is not supported. -95 GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTEThe certificate has unsupported attributes. -96 GNUTLS_E_UNKNOWN_HASH_ALGORITHMThe hash algorithm is unknown. -97 GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPEThe PKCS structure's content type is unknown. -98 GNUTLS_E_UNKNOWN_PKCS_BAG_TYPEThe PKCS structure's bag type is unknown. -99 GNUTLS_E_INVALID_PASSWORD The given password contains invalid characters. -100 GNUTLS_E_MAC_VERIFY_FAILED The Message Authentication Code verification failed. -101 GNUTLS_E_CONSTRAINT_ERROR Some constraint limits were reached. -102 GNUTLS_E_WARNING_IA_IPHF_RECEIVEDReceived a TLS/IA Intermediate Phase Finished message -103 GNUTLS_E_WARNING_IA_FPHF_RECEIVEDReceived a TLS/IA Final Phase Finished message -104 GNUTLS_E_IA_VERIFY_FAILED Verifying TLS/IA phase checksum failed -105 GNUTLS_E_UNKNOWN_ALGORITHM The specified algorithm or protocol is unknown. -106 GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHMThe signature algorithm is not supported. -107 GNUTLS_E_SAFE_RENEGOTIATION_FAILEDSafe renegotiation failed. -108 GNUTLS_E_UNSAFE_RENEGOTIATION_DENIEDUnsafe renegotiation denied. -109 GNUTLS_E_UNKNOWN_SRP_USERNAME The SRP username supplied is unknown. -110 GNUTLS_E_PREMATURE_TERMINATIONThe TLS connection was non-properly terminated. -201 GNUTLS_E_BASE64_ENCODING_ERRORBase64 encoding error. -202 GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARYThe crypto library version is too old. -203 GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARYThe tasn1 library version is too old. -204 GNUTLS_E_OPENPGP_KEYRING_ERRORError loading the keyring. -205 GNUTLS_E_X509_UNSUPPORTED_OID The OID is not supported. -206 GNUTLS_E_RANDOM_FAILED Failed to acquire random data. -207 GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERRORBase64 unexpected header error. -208 GNUTLS_E_OPENPGP_SUBKEY_ERROR Could not find OpenPGP subkey. -209 GNUTLS_E_CRYPTO_ALREADY_REGISTEREDThere is already a crypto algorithm with lower priority. -210 GNUTLS_E_HANDSHAKE_TOO_LARGE The handshake data size is too large. -211 GNUTLS_E_CRYPTODEV_IOCTL_ERRORError interfacing with /dev/crypto -212 GNUTLS_E_CRYPTODEV_DEVICE_ERRORError opening /dev/crypto -213 GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLEChannel binding data not available -214 GNUTLS_E_BAD_COOKIE The cookie was bad. -215 GNUTLS_E_OPENPGP_PREFERRED_KEY_ERRORThe OpenPGP key has not a preferred key set. -216 GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOLThe given DSA key is incompatible with the selected TLS protocol. -292 GNUTLS_E_HEARTBEAT_PONG_RECEIVEDA heartbeat pong message was received. -293 GNUTLS_E_HEARTBEAT_PING_RECEIVEDA heartbeat ping message was received. -300 GNUTLS_E_PKCS11_ERROR PKCS #11 error. -301 GNUTLS_E_PKCS11_LOAD_ERROR PKCS #11 initialization error. -302 GNUTLS_E_PARSING_ERROR Error in parsing. -303 GNUTLS_E_PKCS11_PIN_ERROR Error in provided PIN. -305 GNUTLS_E_PKCS11_SLOT_ERROR PKCS #11 error in slot -306 GNUTLS_E_LOCKING_ERROR Thread locking error -307 GNUTLS_E_PKCS11_ATTRIBUTE_ERRORPKCS #11 error in attribute -308 GNUTLS_E_PKCS11_DEVICE_ERROR PKCS #11 error in device -309 GNUTLS_E_PKCS11_DATA_ERROR PKCS #11 error in data -310 GNUTLS_E_PKCS11_UNSUPPORTED_FEATURE_ERRORPKCS #11 unsupported feature -311 GNUTLS_E_PKCS11_KEY_ERROR PKCS #11 error in key -312 GNUTLS_E_PKCS11_PIN_EXPIRED PKCS #11 PIN expired -313 GNUTLS_E_PKCS11_PIN_LOCKED PKCS #11 PIN locked -314 GNUTLS_E_PKCS11_SESSION_ERROR PKCS #11 error in session -315 GNUTLS_E_PKCS11_SIGNATURE_ERRORPKCS #11 error in signature -316 GNUTLS_E_PKCS11_TOKEN_ERROR PKCS #11 error in token -317 GNUTLS_E_PKCS11_USER_ERROR PKCS #11 user error -318 GNUTLS_E_CRYPTO_INIT_FAILED The initialization of crypto backend has failed. -319 GNUTLS_E_TIMEDOUT The operation timed out -320 GNUTLS_E_USER_ERROR The operation was cancelled due to user error -321 GNUTLS_E_ECC_NO_SUPPORTED_CURVESNo supported ECC curves were found -322 GNUTLS_E_ECC_UNSUPPORTED_CURVEThe curve is unsupported -323 GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLEThe requested PKCS #11 object is not available -324 GNUTLS_E_CERTIFICATE_LIST_UNSORTEDThe provided X.509 certificate list is not sorted (in subject to issuer order) -325 GNUTLS_E_ILLEGAL_PARAMETER An illegal parameter was found. -326 GNUTLS_E_NO_PRIORITIES_WERE_SETNo or insufficient priorities were set. -327 GNUTLS_E_X509_UNSUPPORTED_EXTENSIONUnsupported extension in X.509 certificate. -328 GNUTLS_E_SESSION_EOF Peer has terminated the connection -329 GNUTLS_E_TPM_ERROR TPM error. -330 GNUTLS_E_TPM_KEY_PASSWORD_ERRORError in provided password for key to be loaded in TPM. -331 GNUTLS_E_TPM_SRK_PASSWORD_ERRORError in provided SRK password for TPM. -332 GNUTLS_E_TPM_SESSION_ERROR Cannot initialize a session with the TPM. -333 GNUTLS_E_TPM_KEY_NOT_FOUND TPM key was not found in persistent storage. -334 GNUTLS_E_TPM_UNINITIALIZED TPM is not initialized. -340 GNUTLS_E_NO_CERTIFICATE_STATUSThere is no certificate status (OCSP). -341 GNUTLS_E_OCSP_RESPONSE_ERROR The OCSP response is invalid -342 GNUTLS_E_RANDOM_DEVICE_ERROR Error in the system's randomness device. -343 GNUTLS_E_AUTH_ERROR Could not authenticate peer. -344 GNUTLS_E_NO_APPLICATION_PROTOCOLNo common application protocol could be negotiated.  File: gnutls.info, Node: Supported ciphersuites, Next: API reference, Prev: Error codes, Up: Top Appendix D Supported Ciphersuites ********************************* Ciphersuites ============ Ciphersuite name TLS ID Since -------------------------------------------------------------------------- TLS_RSA_NULL_MD5 0x00 0x01 SSL3.0 TLS_RSA_NULL_SHA1 0x00 0x02 SSL3.0 TLS_RSA_NULL_SHA256 0x00 0x3B TLS1.0 TLS_RSA_ARCFOUR_128_SHA1 0x00 0x05 SSL3.0 TLS_RSA_ARCFOUR_128_MD5 0x00 0x04 SSL3.0 TLS_RSA_3DES_EDE_CBC_SHA1 0x00 0x0A SSL3.0 TLS_RSA_AES_128_CBC_SHA1 0x00 0x2F SSL3.0 TLS_RSA_AES_256_CBC_SHA1 0x00 0x35 SSL3.0 TLS_RSA_CAMELLIA_128_CBC_SHA256 0x00 0xBA TLS1.0 TLS_RSA_CAMELLIA_256_CBC_SHA256 0x00 0xC0 TLS1.0 TLS_RSA_CAMELLIA_128_CBC_SHA1 0x00 0x41 SSL3.0 TLS_RSA_CAMELLIA_256_CBC_SHA1 0x00 0x84 SSL3.0 TLS_RSA_AES_128_CBC_SHA256 0x00 0x3C TLS1.0 TLS_RSA_AES_256_CBC_SHA256 0x00 0x3D TLS1.0 TLS_RSA_AES_128_GCM_SHA256 0x00 0x9C TLS1.2 TLS_RSA_AES_256_GCM_SHA384 0x00 0x9D TLS1.2 TLS_RSA_CAMELLIA_128_GCM_SHA256 0xC0 0x7A TLS1.2 TLS_RSA_CAMELLIA_256_GCM_SHA384 0xC0 0x7B TLS1.2 TLS_RSA_SALSA20_256_SHA1 0xE4 0x11 SSL3.0 TLS_RSA_SALSA20_256_UMAC96 0xE4 0x31 SSL3.0 TLS_RSA_ESTREAM_SALSA20_256_SHA1 0xE4 0x10 SSL3.0 TLS_RSA_ESTREAM_SALSA20_256_UMAC96 0xE4 0x30 SSL3.0 TLS_DHE_DSS_ARCFOUR_128_SHA1 0x00 0x66 SSL3.0 TLS_DHE_DSS_3DES_EDE_CBC_SHA1 0x00 0x13 SSL3.0 TLS_DHE_DSS_AES_128_CBC_SHA1 0x00 0x32 SSL3.0 TLS_DHE_DSS_AES_256_CBC_SHA1 0x00 0x38 SSL3.0 TLS_DHE_DSS_CAMELLIA_128_CBC_SHA256 0x00 0xBD TLS1.0 TLS_DHE_DSS_CAMELLIA_256_CBC_SHA256 0x00 0xC3 TLS1.0 TLS_DHE_DSS_CAMELLIA_128_CBC_SHA1 0x00 0x44 SSL3.0 TLS_DHE_DSS_CAMELLIA_256_CBC_SHA1 0x00 0x87 SSL3.0 TLS_DHE_DSS_AES_128_CBC_SHA256 0x00 0x40 TLS1.0 TLS_DHE_DSS_AES_256_CBC_SHA256 0x00 0x6A TLS1.0 TLS_DHE_DSS_AES_128_GCM_SHA256 0x00 0xA2 TLS1.2 TLS_DHE_DSS_AES_256_GCM_SHA384 0x00 0xA3 TLS1.2 TLS_DHE_DSS_CAMELLIA_128_GCM_SHA256 0xC0 0x80 TLS1.2 TLS_DHE_DSS_CAMELLIA_256_GCM_SHA384 0xC0 0x81 TLS1.2 TLS_DHE_RSA_3DES_EDE_CBC_SHA1 0x00 0x16 SSL3.0 TLS_DHE_RSA_AES_128_CBC_SHA1 0x00 0x33 SSL3.0 TLS_DHE_RSA_AES_256_CBC_SHA1 0x00 0x39 SSL3.0 TLS_DHE_RSA_CAMELLIA_128_CBC_SHA256 0x00 0xBE TLS1.0 TLS_DHE_RSA_CAMELLIA_256_CBC_SHA256 0x00 0xC4 TLS1.0 TLS_DHE_RSA_CAMELLIA_128_CBC_SHA1 0x00 0x45 SSL3.0 TLS_DHE_RSA_CAMELLIA_256_CBC_SHA1 0x00 0x88 SSL3.0 TLS_DHE_RSA_AES_128_CBC_SHA256 0x00 0x67 TLS1.0 TLS_DHE_RSA_AES_256_CBC_SHA256 0x00 0x6B TLS1.0 TLS_DHE_RSA_AES_128_GCM_SHA256 0x00 0x9E TLS1.2 TLS_DHE_RSA_AES_256_GCM_SHA384 0x00 0x9F TLS1.2 TLS_DHE_RSA_CAMELLIA_128_GCM_SHA256 0xC0 0x7C TLS1.2 TLS_DHE_RSA_CAMELLIA_256_GCM_SHA384 0xC0 0x7D TLS1.2 TLS_ECDHE_RSA_NULL_SHA1 0xC0 0x10 SSL3.0 TLS_ECDHE_RSA_3DES_EDE_CBC_SHA1 0xC0 0x12 SSL3.0 TLS_ECDHE_RSA_AES_128_CBC_SHA1 0xC0 0x13 SSL3.0 TLS_ECDHE_RSA_AES_256_CBC_SHA1 0xC0 0x14 SSL3.0 TLS_ECDHE_RSA_AES_256_CBC_SHA384 0xC0 0x28 TLS1.0 TLS_ECDHE_RSA_ARCFOUR_128_SHA1 0xC0 0x11 SSL3.0 TLS_ECDHE_RSA_CAMELLIA_128_CBC_SHA256 0xC0 0x76 TLS1.0 TLS_ECDHE_RSA_CAMELLIA_256_CBC_SHA384 0xC0 0x77 TLS1.0 TLS_ECDHE_ECDSA_NULL_SHA1 0xC0 0x06 SSL3.0 TLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA1 0xC0 0x08 SSL3.0 TLS_ECDHE_ECDSA_AES_128_CBC_SHA1 0xC0 0x09 SSL3.0 TLS_ECDHE_ECDSA_AES_256_CBC_SHA1 0xC0 0x0A SSL3.0 TLS_ECDHE_ECDSA_ARCFOUR_128_SHA1 0xC0 0x07 SSL3.0 TLS_ECDHE_ECDSA_CAMELLIA_128_CBC_SHA256 0xC0 0x72 TLS1.0 TLS_ECDHE_ECDSA_CAMELLIA_256_CBC_SHA384 0xC0 0x73 TLS1.0 TLS_ECDHE_ECDSA_AES_128_CBC_SHA256 0xC0 0x23 TLS1.0 TLS_ECDHE_RSA_AES_128_CBC_SHA256 0xC0 0x27 TLS1.0 TLS_ECDHE_ECDSA_CAMELLIA_128_GCM_SHA256 0xC0 0x86 TLS1.2 TLS_ECDHE_ECDSA_CAMELLIA_256_GCM_SHA384 0xC0 0x87 TLS1.2 TLS_ECDHE_ECDSA_AES_128_GCM_SHA256 0xC0 0x2B TLS1.2 TLS_ECDHE_ECDSA_AES_256_GCM_SHA384 0xC0 0x2C TLS1.2 TLS_ECDHE_RSA_AES_128_GCM_SHA256 0xC0 0x2F TLS1.2 TLS_ECDHE_RSA_AES_256_GCM_SHA384 0xC0 0x30 TLS1.2 TLS_ECDHE_ECDSA_AES_256_CBC_SHA384 0xC0 0x24 TLS1.0 TLS_ECDHE_RSA_CAMELLIA_128_GCM_SHA256 0xC0 0x8A TLS1.2 TLS_ECDHE_RSA_CAMELLIA_256_GCM_SHA384 0xC0 0x8B TLS1.2 TLS_ECDHE_RSA_SALSA20_256_SHA1 0xE4 0x13 SSL3.0 TLS_ECDHE_RSA_SALSA20_256_UMAC96 0xE4 0x33 SSL3.0 TLS_ECDHE_ECDSA_SALSA20_256_SHA1 0xE4 0x15 SSL3.0 TLS_ECDHE_ECDSA_SALSA20_256_UMAC96 0xE4 0x35 SSL3.0 TLS_ECDHE_RSA_ESTREAM_SALSA20_256_SHA1 0xE4 0x12 SSL3.0 TLS_ECDHE_RSA_ESTREAM_SALSA20_256_UMAC96 0xE4 0x32 SSL3.0 TLS_ECDHE_ECDSA_ESTREAM_SALSA20_256_SHA1 0xE4 0x14 SSL3.0 TLS_ECDHE_ECDSA_ESTREAM_SALSA20_256_UMAC96 0xE4 0x34 SSL3.0 TLS_ECDHE_PSK_3DES_EDE_CBC_SHA1 0xC0 0x34 SSL3.0 TLS_ECDHE_PSK_AES_128_CBC_SHA1 0xC0 0x35 SSL3.0 TLS_ECDHE_PSK_AES_256_CBC_SHA1 0xC0 0x36 SSL3.0 TLS_ECDHE_PSK_AES_128_CBC_SHA256 0xC0 0x37 TLS1.0 TLS_ECDHE_PSK_AES_256_CBC_SHA384 0xC0 0x38 TLS1.0 TLS_ECDHE_PSK_ARCFOUR_128_SHA1 0xC0 0x33 SSL3.0 TLS_ECDHE_PSK_NULL_SHA256 0xC0 0x3A TLS1.0 TLS_ECDHE_PSK_NULL_SHA384 0xC0 0x3B TLS1.0 TLS_ECDHE_PSK_CAMELLIA_128_CBC_SHA256 0xC0 0x9A TLS1.0 TLS_ECDHE_PSK_CAMELLIA_256_CBC_SHA384 0xC0 0x9B TLS1.0 TLS_ECDHE_PSK_SALSA20_256_SHA1 0xE4 0x19 SSL3.0 TLS_ECDHE_PSK_SALSA20_256_UMAC96 0xE4 0x39 SSL3.0 TLS_ECDHE_PSK_ESTREAM_SALSA20_256_SHA1 0xE4 0x18 SSL3.0 TLS_ECDHE_PSK_ESTREAM_SALSA20_256_UMAC96 0xE4 0x38 SSL3.0 TLS_PSK_ARCFOUR_128_SHA1 0x00 0x8A SSL3.0 TLS_PSK_3DES_EDE_CBC_SHA1 0x00 0x8B SSL3.0 TLS_PSK_AES_128_CBC_SHA1 0x00 0x8C SSL3.0 TLS_PSK_AES_256_CBC_SHA1 0x00 0x8D SSL3.0 TLS_PSK_AES_128_CBC_SHA256 0x00 0xAE TLS1.0 TLS_PSK_AES_256_GCM_SHA384 0x00 0xA9 TLS1.2 TLS_PSK_CAMELLIA_128_GCM_SHA256 0xC0 0x8E TLS1.2 TLS_PSK_CAMELLIA_256_GCM_SHA384 0xC0 0x8F TLS1.2 TLS_PSK_AES_128_GCM_SHA256 0x00 0xA8 TLS1.2 TLS_PSK_NULL_SHA256 0x00 0xB0 TLS1.0 TLS_PSK_CAMELLIA_128_CBC_SHA256 0xC0 0x94 TLS1.0 TLS_PSK_CAMELLIA_256_CBC_SHA384 0xC0 0x95 TLS1.0 TLS_PSK_SALSA20_256_SHA1 0xE4 0x17 SSL3.0 TLS_PSK_SALSA20_256_UMAC96 0xE4 0x37 SSL3.0 TLS_PSK_ESTREAM_SALSA20_256_SHA1 0xE4 0x16 SSL3.0 TLS_PSK_ESTREAM_SALSA20_256_UMAC96 0xE4 0x36 SSL3.0 TLS_PSK_AES_256_CBC_SHA384 0x00 0xAF TLS1.0 TLS_PSK_NULL_SHA384 0x00 0xB1 TLS1.0 TLS_RSA_PSK_ARCFOUR_128_SHA1 0x00 0x92 SSL3.0 TLS_RSA_PSK_3DES_EDE_CBC_SHA1 0x00 0x93 SSL3.0 TLS_RSA_PSK_AES_128_CBC_SHA1 0x00 0x94 SSL3.0 TLS_RSA_PSK_AES_256_CBC_SHA1 0x00 0x95 SSL3.0 TLS_RSA_PSK_CAMELLIA_128_GCM_SHA256 0xC0 0x92 TLS1.2 TLS_RSA_PSK_CAMELLIA_256_GCM_SHA384 0xC0 0x93 TLS1.2 TLS_RSA_PSK_AES_128_GCM_SHA256 0x00 0xAC TLS1.2 TLS_RSA_PSK_AES_128_CBC_SHA256 0x00 0xB6 TLS1.0 TLS_RSA_PSK_NULL_SHA256 0x00 0xB8 TLS1.0 TLS_RSA_PSK_AES_256_GCM_SHA384 0x00 0xAD TLS1.2 TLS_RSA_PSK_AES_256_CBC_SHA384 0x00 0xB7 TLS1.0 TLS_RSA_PSK_NULL_SHA384 0x00 0xB9 TLS1.0 TLS_RSA_PSK_CAMELLIA_128_CBC_SHA256 0xC0 0x98 TLS1.0 TLS_RSA_PSK_CAMELLIA_256_CBC_SHA384 0xC0 0x99 TLS1.0 TLS_DHE_PSK_ARCFOUR_128_SHA1 0x00 0x8E SSL3.0 TLS_DHE_PSK_3DES_EDE_CBC_SHA1 0x00 0x8F SSL3.0 TLS_DHE_PSK_AES_128_CBC_SHA1 0x00 0x90 SSL3.0 TLS_DHE_PSK_AES_256_CBC_SHA1 0x00 0x91 SSL3.0 TLS_DHE_PSK_AES_128_CBC_SHA256 0x00 0xB2 TLS1.0 TLS_DHE_PSK_AES_128_GCM_SHA256 0x00 0xAA TLS1.2 TLS_DHE_PSK_NULL_SHA256 0x00 0xB4 TLS1.0 TLS_DHE_PSK_NULL_SHA384 0x00 0xB5 TLS1.0 TLS_DHE_PSK_AES_256_CBC_SHA384 0x00 0xB3 TLS1.0 TLS_DHE_PSK_AES_256_GCM_SHA384 0x00 0xAB TLS1.2 TLS_DHE_PSK_CAMELLIA_128_CBC_SHA256 0xC0 0x96 TLS1.0 TLS_DHE_PSK_CAMELLIA_256_CBC_SHA384 0xC0 0x97 TLS1.0 TLS_DHE_PSK_CAMELLIA_128_GCM_SHA256 0xC0 0x90 TLS1.2 TLS_DHE_PSK_CAMELLIA_256_GCM_SHA384 0xC0 0x91 TLS1.2 TLS_DH_ANON_ARCFOUR_128_MD5 0x00 0x18 SSL3.0 TLS_DH_ANON_3DES_EDE_CBC_SHA1 0x00 0x1B SSL3.0 TLS_DH_ANON_AES_128_CBC_SHA1 0x00 0x34 SSL3.0 TLS_DH_ANON_AES_256_CBC_SHA1 0x00 0x3A SSL3.0 TLS_DH_ANON_CAMELLIA_128_CBC_SHA256 0x00 0xBF TLS1.0 TLS_DH_ANON_CAMELLIA_256_CBC_SHA256 0x00 0xC5 TLS1.0 TLS_DH_ANON_CAMELLIA_128_CBC_SHA1 0x00 0x46 SSL3.0 TLS_DH_ANON_CAMELLIA_256_CBC_SHA1 0x00 0x89 SSL3.0 TLS_DH_ANON_AES_128_CBC_SHA256 0x00 0x6C TLS1.0 TLS_DH_ANON_AES_256_CBC_SHA256 0x00 0x6D TLS1.0 TLS_DH_ANON_AES_128_GCM_SHA256 0x00 0xA6 TLS1.2 TLS_DH_ANON_AES_256_GCM_SHA384 0x00 0xA7 TLS1.2 TLS_DH_ANON_CAMELLIA_128_GCM_SHA256 0xC0 0x84 TLS1.2 TLS_DH_ANON_CAMELLIA_256_GCM_SHA384 0xC0 0x85 TLS1.2 TLS_ECDH_ANON_NULL_SHA1 0xC0 0x15 SSL3.0 TLS_ECDH_ANON_3DES_EDE_CBC_SHA1 0xC0 0x17 SSL3.0 TLS_ECDH_ANON_AES_128_CBC_SHA1 0xC0 0x18 SSL3.0 TLS_ECDH_ANON_AES_256_CBC_SHA1 0xC0 0x19 SSL3.0 TLS_ECDH_ANON_ARCFOUR_128_SHA1 0xC0 0x16 SSL3.0 TLS_SRP_SHA_3DES_EDE_CBC_SHA1 0xC0 0x1A SSL3.0 TLS_SRP_SHA_AES_128_CBC_SHA1 0xC0 0x1D SSL3.0 TLS_SRP_SHA_AES_256_CBC_SHA1 0xC0 0x20 SSL3.0 TLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1 0xC0 0x1C SSL3.0 TLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1 0xC0 0x1B SSL3.0 TLS_SRP_SHA_DSS_AES_128_CBC_SHA1 0xC0 0x1F SSL3.0 TLS_SRP_SHA_RSA_AES_128_CBC_SHA1 0xC0 0x1E SSL3.0 TLS_SRP_SHA_DSS_AES_256_CBC_SHA1 0xC0 0x22 SSL3.0 TLS_SRP_SHA_RSA_AES_256_CBC_SHA1 0xC0 0x21 SSL3.0 Certificate types ================= 'X.509' 'OPENPGP' Protocols ========= 'SSL3.0' 'TLS1.0' 'TLS1.1' 'TLS1.2' 'DTLS0.9' 'DTLS1.0' 'DTLS1.2' Ciphers ======= 'AES-256-CBC' 'AES-192-CBC' 'AES-128-CBC' 'AES-128-GCM' 'AES-256-GCM' 'ARCFOUR-128' 'ESTREAM-SALSA20-256' 'SALSA20-256' 'CAMELLIA-256-CBC' 'CAMELLIA-192-CBC' 'CAMELLIA-128-CBC' 'CAMELLIA-128-GCM' 'CAMELLIA-256-GCM' '3DES-CBC' 'DES-CBC' 'ARCFOUR-40' 'RC2-40' MAC algorithms ============== 'SHA1' 'MD5' 'SHA256' 'SHA384' 'SHA512' 'SHA224' 'UMAC-96' 'UMAC-128' 'AEAD' Key exchange methods ==================== 'ANON-DH' 'ANON-ECDH' 'RSA' 'DHE-RSA' 'DHE-DSS' 'ECDHE-RSA' 'ECDHE-ECDSA' 'SRP-DSS' 'SRP-RSA' 'SRP' 'PSK' 'RSA-PSK' 'DHE-PSK' 'ECDHE-PSK' Public key algorithms ===================== 'RSA' 'DSA' 'EC' Public key signature algorithms =============================== 'RSA-SHA1' 'RSA-SHA1' 'RSA-SHA224' 'RSA-SHA256' 'RSA-SHA384' 'RSA-SHA512' 'RSA-RMD160' 'DSA-SHA1' 'DSA-SHA1' 'DSA-SHA224' 'DSA-SHA256' 'RSA-MD5' 'RSA-MD5' 'RSA-MD2' 'ECDSA-SHA1' 'ECDSA-SHA224' 'ECDSA-SHA256' 'ECDSA-SHA384' 'ECDSA-SHA512' Elliptic curves =============== 'SECP192R1' 'SECP224R1' 'SECP256R1' 'SECP384R1' 'SECP521R1' Compression methods =================== 'DEFLATE' 'NULL'