From dea76650aa0e7f0034650e5c0c43f77ea6eb17a3 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:22:38 +0000 Subject: [PATCH 1/8] Removed pitfalls mentioned for old versions of GnuTLS Also removed text about explicit initialization no longer applicable. That text did not apply in any recent Fedora or on RHEL7. --- diff --git a/en-US/Features-TLS.xml b/en-US/Features-TLS.xml index a2c0afd..ebdd83d 100644 --- a/en-US/Features-TLS.xml +++ b/en-US/Features-TLS.xml @@ -215,58 +215,10 @@
GNUTLS Pitfalls - Older versions of GNUTLS had several peculiarities. As of - GNUTLS 3.3.10, they have been addressed, so these are only a - concern for applications which have to run with older GNUTLS - versions. + Older versions of GNUTLS had several peculiarities described + in previous versions of this guide; as of GNUTLS 3.3.10, these + issues are no longer applicable. - - - - The dynamic shared object provided by GNTULS links to - libpthread.so.0. Loading the - threading library too late causes problems, so the main - program should be linked with -lpthread - as well. As a result, it can be difficult to use GNUTLS - in a plugin which is loaded with the - dlopen function. Another side effect - is that applications which merely link against GNUTLS - (even without actually using it) may incur a substantial - overhead because other libraries automatically switch to - thread-safe algorithms. - - - - - The gnutls_global_init function must - be called before using any functionality provided by the - library. This function is not thread-safe, so external - locking is required, but it is not clear which lock should - be used. Omitting the synchronization does not just lead - to a memory leak, as it is suggested in the GNUTLS - documentation, but to undefined behavior because there is - no barrier that would enforce memory ordering. - - - - - The gnutls_global_deinit function - does not actually deallocate all resources allocated by - gnutls_global_init. It is currently - not thread-safe. Therefore, it is best to avoid calling - it altogether. - - - - - The X.509 implementation in GNUTLS is rather lenient. For - example, it is possible to create and process X.509 - version 1 certificates which carry extensions. These - certificates are (correctly) rejected by other - implementations. - - -
OpenJDK Pitfalls @@ -522,19 +474,6 @@ exploratory and needs to be replaced before production use. - The GNUTLS library needs explicit initialization: - - - - - - Failing to do so can result in obscure failures in Base64 - decoding. See for - additional aspects of initialization. - - Before setting up TLS connections, a credentials objects has to be allocated and initialized with the set of trusted root CAs ( +// This is only necessary if compatibility with GnuTLS prior to +// 3.3.0 is required. gnutls_global_init(); diff --git a/src/TLS-Client-GNUTLS.c b/src/TLS-Client-GNUTLS.c index 4ee2c82..77da93b 100644 --- a/src/TLS-Client-GNUTLS.c +++ b/src/TLS-Client-GNUTLS.c @@ -84,6 +84,8 @@ main(int argc, char **argv) } //+ Features TLS-GNUTLS-Init + // This is only necessary if compatibility with GnuTLS prior to + // 3.3.0 is required. gnutls_global_init(); //- From b1f32880486b7b88246b56e6cec46c0001338c84 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:22:45 +0000 Subject: [PATCH 2/8] mention TLS in Transport Layer Security section title --- diff --git a/en-US/Features-TLS.xml b/en-US/Features-TLS.xml index ebdd83d..4758e83 100644 --- a/en-US/Features-TLS.xml +++ b/en-US/Features-TLS.xml @@ -2,7 +2,7 @@ - Transport Layer Security + Transport Layer Security (TLS) Transport Layer Security (TLS, formerly Secure Sockets Layer/SSL) is the recommended way to to protect integrity and From 554750316e15c28402572c4f91b74ceceb6bce27 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:22:49 +0000 Subject: [PATCH 3/8] TLS: gnutls: use gnutls_certificate_set_x509_system_trust Avoid hard-coding any paths and use the function which is portable across operating systems. --- diff --git a/en-US/snippets/Features-TLS-Client-GNUTLS-Credentials.xml b/en-US/snippets/Features-TLS-Client-GNUTLS-Credentials.xml index 6a5cd09..f69f552 100644 --- a/en-US/snippets/Features-TLS-Client-GNUTLS-Credentials.xml +++ b/en-US/snippets/Features-TLS-Client-GNUTLS-Credentials.xml @@ -11,19 +11,15 @@ if (ret != GNUTLS_E_SUCCESS) { gnutls_strerror(ret)); exit(1); } -// gnutls_certificate_set_x509_system_trust needs GNUTLS version 3.0 -// or newer, so we hard-code the path to the certificate store -// instead. -static const char ca_bundle[] = "/etc/ssl/certs/ca-bundle.crt"; -ret = gnutls_certificate_set_x509_trust_file - (cred, ca_bundle, GNUTLS_X509_FMT_PEM); + +ret = gnutls_certificate_set_x509_system_trust(cred); if (ret == 0) { - fprintf(stderr, "error: no certificates found in: %s\n", ca_bundle); + fprintf(stderr, "error: no certificates found in system trust store\n"); exit(1); } if (ret < 0) { - fprintf(stderr, "error: gnutls_certificate_set_x509_trust_files(%s): %s\n", - ca_bundle, gnutls_strerror(ret)); + fprintf(stderr, "error: gnutls_certificate_set_x509_system_trust: %s\n", + gnutls_strerror(ret)); exit(1); } diff --git a/src/TLS-Client-GNUTLS.c b/src/TLS-Client-GNUTLS.c index 77da93b..b0f5ce6 100644 --- a/src/TLS-Client-GNUTLS.c +++ b/src/TLS-Client-GNUTLS.c @@ -98,19 +98,15 @@ main(int argc, char **argv) gnutls_strerror(ret)); exit(1); } - // gnutls_certificate_set_x509_system_trust needs GNUTLS version 3.0 - // or newer, so we hard-code the path to the certificate store - // instead. - static const char ca_bundle[] = "/etc/ssl/certs/ca-bundle.crt"; - ret = gnutls_certificate_set_x509_trust_file - (cred, ca_bundle, GNUTLS_X509_FMT_PEM); + + ret = gnutls_certificate_set_x509_system_trust(cred); if (ret == 0) { - fprintf(stderr, "error: no certificates found in: %s\n", ca_bundle); + fprintf(stderr, "error: no certificates found in system trust store\n"); exit(1); } if (ret < 0) { - fprintf(stderr, "error: gnutls_certificate_set_x509_trust_files(%s): %s\n", - ca_bundle, gnutls_strerror(ret)); + fprintf(stderr, "error: gnutls_certificate_set_x509_system_trust: %s\n", + gnutls_strerror(ret)); exit(1); } //- From 1c84959ddbc00d09a64771e563ab60a68011cfcd Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:22:52 +0000 Subject: [PATCH 4/8] Mention only gnutls_certificate_verify_peers3() Also use gnutls_transport_set_int() which requires no casts. Also remove any description of code no longer applicable in Fedora 2X or RHEL7. --- diff --git a/en-US/Features-TLS.xml b/en-US/Features-TLS.xml index 4758e83..1789853 100644 --- a/en-US/Features-TLS.xml +++ b/en-US/Features-TLS.xml @@ -515,7 +515,7 @@ After the handshake has been completed, the server certificate - needs to be verified (). In the example, the user-defined certificate_validity_override function is @@ -529,29 +529,6 @@ xmlns:xi="http://www.w3.org/2001/XInclude" /> - In the next step (, the - certificate must be matched against the host name (note the - unusual return value from - gnutls_x509_crt_check_hostname). Again, - an override function - certificate_host_name_override is called. - Note that the override must be keyed to the certificate - and the host name. The function call can - be omitted if the override is not needed. - - - Matching the server host name and certificate in a - GNUTLS client - - - - In newer GNUTLS versions, certificate checking and host name - validation can be combined using the - gnutls_certificate_verify_peers3 function. - - An established TLS session can be used for sending and receiving data, as in . diff --git a/en-US/snippets/Features-TLS-Client-GNUTLS-Connect.xml b/en-US/snippets/Features-TLS-Client-GNUTLS-Connect.xml index fbf1420..390405e 100644 --- a/en-US/snippets/Features-TLS-Client-GNUTLS-Connect.xml +++ b/en-US/snippets/Features-TLS-Client-GNUTLS-Connect.xml @@ -31,7 +31,7 @@ if (ret != GNUTLS_E_SUCCESS) { // Associate the socket with the session object and set the server // name. -gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t)(uintptr_t)sockfd); +gnutls_transport_set_int(session, sockfd); ret = gnutls_server_name_set(session, GNUTLS_NAME_DNS, host, strlen(host)); if (ret != GNUTLS_E_SUCCESS) { diff --git a/en-US/snippets/Features-TLS-Client-GNUTLS-Verify.xml b/en-US/snippets/Features-TLS-Client-GNUTLS-Verify.xml index a3c9365..eb89535 100644 --- a/en-US/snippets/Features-TLS-Client-GNUTLS-Verify.xml +++ b/en-US/snippets/Features-TLS-Client-GNUTLS-Verify.xml @@ -15,9 +15,9 @@ if (certs == NULL || certslen == 0) { // Validate the certificate chain. unsigned status = (unsigned)-1; -ret = gnutls_certificate_verify_peers2(session, &status); +ret = gnutls_certificate_verify_peers3(session, host, &status); if (ret != GNUTLS_E_SUCCESS) { - fprintf(stderr, "error: gnutls_certificate_verify_peers2: %s\n", + fprintf(stderr, "error: gnutls_certificate_verify_peers3: %s\n", gnutls_strerror(ret)); exit(1); } diff --git a/src/TLS-Client-GNUTLS.c b/src/TLS-Client-GNUTLS.c index b0f5ce6..7c0fa7b 100644 --- a/src/TLS-Client-GNUTLS.c +++ b/src/TLS-Client-GNUTLS.c @@ -160,7 +160,7 @@ main(int argc, char **argv) // Associate the socket with the session object and set the server // name. - gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t)(uintptr_t)sockfd); + gnutls_transport_set_int(session, sockfd); ret = gnutls_server_name_set(session, GNUTLS_NAME_DNS, host, strlen(host)); if (ret != GNUTLS_E_SUCCESS) { @@ -191,9 +191,9 @@ main(int argc, char **argv) // Validate the certificate chain. unsigned status = (unsigned)-1; - ret = gnutls_certificate_verify_peers2(session, &status); + ret = gnutls_certificate_verify_peers3(session, host, &status); if (ret != GNUTLS_E_SUCCESS) { - fprintf(stderr, "error: gnutls_certificate_verify_peers2: %s\n", + fprintf(stderr, "error: gnutls_certificate_verify_peers3: %s\n", gnutls_strerror(ret)); exit(1); } @@ -217,33 +217,6 @@ main(int argc, char **argv) } //- - //+ Features TLS-Client-GNUTLS-Match - // Match the peer certificate against the host name. - // We can only obtain a set of DER-encoded certificates from the - // session object, so we have to re-parse the peer certificate into - // a certificate object. - gnutls_x509_crt_t cert; - ret = gnutls_x509_crt_init(&cert); - if (ret != GNUTLS_E_SUCCESS) { - fprintf(stderr, "error: gnutls_x509_crt_init: %s\n", - gnutls_strerror(ret)); - exit(1); - } - // The peer certificate is the first certificate in the list. - ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER); - if (ret != GNUTLS_E_SUCCESS) { - fprintf(stderr, "error: gnutls_x509_crt_import: %s\n", - gnutls_strerror(ret)); - exit(1); - } - ret = gnutls_x509_crt_check_hostname(cert, host); - if (ret == 0 && !certificate_host_name_override(certs[0], host)) { - fprintf(stderr, "error: host name does not match certificate\n"); - exit(1); - } - gnutls_x509_crt_deinit(cert); - //- - //+ Features TLS-GNUTLS-Use char buf[4096]; snprintf(buf, sizeof(buf), "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", host); From a69cea175c4059de3736dd138c0d6160703b7370 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:22:54 +0000 Subject: [PATCH 5/8] TLS: document the update-ca-trust --- diff --git a/en-US/Features-TLS.xml b/en-US/Features-TLS.xml index 1789853..2f4a653 100644 --- a/en-US/Features-TLS.xml +++ b/en-US/Features-TLS.xml @@ -281,16 +281,17 @@ The client must configure the TLS library to use a set of trusted root certificates. These certificates are provided - by the system in /etc/ssl/certs or files derived - from it. + by the system in various formats and files. These are documented in update-ca-trust + man page in Fedora. Portable applications should not hard-code + any paths; they should rely on APIs which set the default + for the system trust store. The client selects sufficiently strong cryptographic primitives and disables insecure ones (such as no-op - encryption). Compression and SSL version 2 support must be + encryption). Compression support and SSL version 3 or lower must be disabled (including the SSLv2-compatible handshake). @@ -546,7 +547,7 @@ linkend="ex-Defensive_Coding-TLS-GNUTLS-Disconnect"/>). - Using a GNUTLS session + Closing a GNUTLS session in an orderly fashion From 0baf3aab19a1df777eb1c47217eea3203fb9560e Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:22:57 +0000 Subject: [PATCH 6/8] TLS-Client-NSS: enable AES-GCM --- diff --git a/en-US/snippets/Features-TLS-NSS-Init.xml b/en-US/snippets/Features-TLS-NSS-Init.xml index 6352282..939ff39 100644 --- a/en-US/snippets/Features-TLS-NSS-Init.xml +++ b/en-US/snippets/Features-TLS-NSS-Init.xml @@ -16,6 +16,14 @@ if (ctx == NULL) { // Ciphers to enable. static const PRUint16 good_ciphers[] = { + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, diff --git a/src/TLS-Client-NSS.c b/src/TLS-Client-NSS.c index 3faac5c..49525a0 100644 --- a/src/TLS-Client-NSS.c +++ b/src/TLS-Client-NSS.c @@ -107,6 +107,14 @@ main(int argc, char **argv) // Ciphers to enable. static const PRUint16 good_ciphers[] = { + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, From f5efbe80bc13ee3ced7ff2ed1f116baaf8f8b8a8 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:23:02 +0000 Subject: [PATCH 7/8] TLS: mention upstream documentation for libraries --- diff --git a/en-US/Features-TLS.xml b/en-US/Features-TLS.xml index 2f4a653..19e3db5 100644 --- a/en-US/Features-TLS.xml +++ b/en-US/Features-TLS.xml @@ -7,8 +7,20 @@ Transport Layer Security (TLS, formerly Secure Sockets Layer/SSL) is the recommended way to to protect integrity and confidentiality while data is transferred over an untrusted - network connection, and to identify the endpoint. + network connection, and to identify the endpoint. At this + chapter we describe the available libraries in Fedora as well + as known pitfalls, and safe ways to write applications with them. + + When using any library, in addition to this guide, it is recommended to consult the + library' documentation. + + + NSS documentation + GNUTLS documentation + OpenSSL documentation + OpenJDK documentation +
Common Pitfalls From 9d525b7fd6528a5905dcd74013f35341d943580d Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Aug 04 2016 06:24:32 +0000 Subject: [PATCH 8/8] TLS: added GNUTLS server example --- diff --git a/en-US/Features-TLS.xml b/en-US/Features-TLS.xml index 19e3db5..4632abf 100644 --- a/en-US/Features-TLS.xml +++ b/en-US/Features-TLS.xml @@ -939,4 +939,138 @@
- +
+ TLS Server + + Secure use of TLS in a server generally involves all of the + following steps. (Individual instructions for specific TLS + implementations follow in the next sections.) + + + + + The server selects sufficiently strong cryptographic + primitives and disables insecure ones (such as no-op + encryption). Compression support and SSL version 3 or lower must be + disabled (including the SSLv2-compatible handshake). + + + + + The server sets its certificate and key files. The server may + have multiple such files, either because it is serving multiple host + names, or because (for example) it has both RSA and ECDSA parameters. + + + + + The server needs to specify an OCSP status request response file. + That is, a response from the certificate issuer's OCSP server which + states that the certificate is valid. This response file should be updated + during the server's operational lifetime. The update frequency depends + on the OCSP server's update frequency. Typically that's between few days + and a week. + + + Setting this file allows the connecting clients to obtain and verify the + OCSP response for the server's certificate as soon, without contacting + third party servers. This is often called a stapled OCSP response, and + it is possible for the server to require his clients to check the OCSP response + by marking his certificate as OCSP MUST-staple (which is defined on + any unfortunately named RFC: "rfc7633: Transport Layer Security (TLS) Feature Extension". + + + +
+ Implementation of TLS Servers With GNUTLS + + While there are several types of TLS Servers, in this example we explore + a basic TLS server where the server is authenticated by the client using + certificate authentication. + + + Before setting up TLS connections, a credentials objects has + to be allocated and initialized with the server's certificate + and keys (). + + + In the case of a Hardware Security Module, the gnutls_certificate_set_x509_key_file + should be provided with PKCS#11 URLs for the key and/or the certificate instead of files. + + + Initializing a GNUTLS credentials structure + + + + Similarly a set of acceptable ciphersuites must be generated + (). + + + Initializing a GNUTLS priorities structure + + + + After the last TLS connection has been closed, these credentials + and priorities cache objects should be freed: + + + + + + During its lifetime, the credentials object can be used to + initialize TLS session objects from multiple threads, provided + that it is not changed. + + + To support session resumption, GNUTLS requires to specify a set of + functions for storage and retrieval of session data. To support resumption + using session tickets (i.e., the client is expected to store its resumption data), + GNUTLS requires to generate an encryption key using gnutls_session_ticket_key_generate + and associate it with a server session with gnutls_session_ticket_enable_server. + We will not explore session resumption in our example. + + + The server may specify whether it requires a client to authenticate + itself using a certificate or not. If a client sends a certificate + the server must verify it similarly to a Client verifying a server's + certificate (). That + verification should occur in a callback set using gnutls_session_set_verify_function. + We will not explore further this option in this guide. + + + Establishing a TLS server connection using GNUTLS + + + + An established TLS session can be used for sending and + receiving data, identically as in the client case . + + + Using a GNUTLS session + + + + To shut down a connection in an orderly manner, you + should call the gnutls_bye function, + and, the session object can be deallocated using + gnutls_deinit. This is similar to the client + case, but in this case the server doesn't wait for the client + reply of the connection (see ). + + + Closing a GNUTLS session in an orderly fashion + + +
+
diff --git a/en-US/snippets/Features-TLS-Server-GNUTLS-Accept.xml b/en-US/snippets/Features-TLS-Server-GNUTLS-Accept.xml new file mode 100644 index 0000000..8aac205 --- /dev/null +++ b/en-US/snippets/Features-TLS-Server-GNUTLS-Accept.xml @@ -0,0 +1,45 @@ + + + + +// Create the session object. +for (;;) { + gnutls_session_t session; + + sa_cli_len = sizeof(sa_cli); + sockfd = accept(listenfd, (struct sockaddr *) &sa_cli, &sa_cli_len); + + ret = gnutls_init(&session, GNUTLS_SERVER); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + // Set the acceptable ciphersuites + ret = gnutls_priority_set(session, priority_cache); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_priority_set: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + // Set the server's certificate object + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_credentials_set: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_certificate_server_set_request(session, GNUTLS_CERT_IGNORE); + + gnutls_transport_set_int(session, sockfd); + + // Establish the session. + ret = gnutls_handshake(session); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_handshake: %s\n", gnutls_strerror(ret)); + exit(1); + } + diff --git a/en-US/snippets/Features-TLS-Server-GNUTLS-Credentials-Close.xml b/en-US/snippets/Features-TLS-Server-GNUTLS-Credentials-Close.xml new file mode 100644 index 0000000..6f7418c --- /dev/null +++ b/en-US/snippets/Features-TLS-Server-GNUTLS-Credentials-Close.xml @@ -0,0 +1,8 @@ + + + + +gnutls_priority_deinit(priority_cache); +gnutls_certificate_free_credentials(cred); + diff --git a/en-US/snippets/Features-TLS-Server-GNUTLS-Credentials.xml b/en-US/snippets/Features-TLS-Server-GNUTLS-Credentials.xml new file mode 100644 index 0000000..e16ff17 --- /dev/null +++ b/en-US/snippets/Features-TLS-Server-GNUTLS-Credentials.xml @@ -0,0 +1,42 @@ + + + + +// Load the trusted CA certificates. +const char *keyfile = argv[2]; +const char *certfile = argv[3]; +const char *ocspfile = NULL; + +if (argc > 4) + ocspfile = argv[4]; + +gnutls_certificate_credentials_t cred = NULL; +int ret = gnutls_certificate_allocate_credentials(&cred); +if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_certificate_allocate_credentials: %s\n", + gnutls_strerror(ret)); + exit(1); +} + +// Set the server certificate and key files. These can be PEM +// files, or PKCS#11 URLs in case an HSM is in use. +ret = + gnutls_certificate_set_x509_key_file(cred, certfile, keyfile, + GNUTLS_X509_FMT_PEM); +if (ret < 0) { + fprintf(stderr, "error: gnutls_certificate_set_x509_key_file: %s\n", + gnutls_strerror(ret)); + exit(1); +} + +if (ocspfile) { + ret = gnutls_certificate_set_ocsp_status_request_file(cred, ocspfile, 0); + if (ret < 0) { + fprintf(stderr, + "error: gnutls_certificate_set_ocsp_status_request_file: %s\n", + gnutls_strerror(ret)); + exit(1); + } +} + diff --git a/en-US/snippets/Features-TLS-Server-GNUTLS-Disconnect.xml b/en-US/snippets/Features-TLS-Server-GNUTLS-Disconnect.xml new file mode 100644 index 0000000..bd02df0 --- /dev/null +++ b/en-US/snippets/Features-TLS-Server-GNUTLS-Disconnect.xml @@ -0,0 +1,14 @@ + + + + +// Initiate an orderly connection shutdown. +ret = gnutls_bye(session, GNUTLS_SHUT_WR); +if (ret < 0) { + fprintf(stderr, "error: gnutls_bye: %s\n", gnutls_strerror(ret)); + exit(1); +} +// Free the session object. +gnutls_deinit(session); + diff --git a/en-US/snippets/Features-TLS-Server-GNUTLS-Priorities.xml b/en-US/snippets/Features-TLS-Server-GNUTLS-Priorities.xml new file mode 100644 index 0000000..bce0b49 --- /dev/null +++ b/en-US/snippets/Features-TLS-Server-GNUTLS-Priorities.xml @@ -0,0 +1,18 @@ + + + + +// Create the ciphersuite priorities object +gnutls_priority_t priority_cache; +const char *errpos = NULL; + +ret = gnutls_priority_init(&priority_cache, "PERFORMANCE:%SERVER_PRECEDENCE", &errpos); +if (ret == GNUTLS_E_PARSING_ERROR) { + fprintf(stderr, "error: gnutls_priority_init parsing error at: %s\n", errpos); + exit(1); +} else if (ret < 0) { + fprintf(stderr, "error: gnutls_priority_init: %s\n", gnutls_strerror(ret)); + exit(1); +} + diff --git a/src/TLS-Server-GNUTLS.c b/src/TLS-Server-GNUTLS.c new file mode 100644 index 0000000..33182ce --- /dev/null +++ b/src/TLS-Server-GNUTLS.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tcp_connect.h" + +static void __attribute__ ((noreturn)) + usage(const char *progname) +{ + fprintf(stderr, "usage: %s PORT KEY CERT OCSP\n", progname); + exit(2); +} + +int main(int argc, char **argv) +{ + if (argc < 4) { + usage(argv[0]); + } + //+ Features TLS-GNUTLS-Init + // This is only necessary if compatibility with GnuTLS prior to + // 3.3.0 is required. + gnutls_global_init(); + //- + + //+ Features TLS-Server-GNUTLS-Credentials + // Load the trusted CA certificates. + const char *keyfile = argv[2]; + const char *certfile = argv[3]; + const char *ocspfile = NULL; + + if (argc > 4) + ocspfile = argv[4]; + + gnutls_certificate_credentials_t cred = NULL; + int ret = gnutls_certificate_allocate_credentials(&cred); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_certificate_allocate_credentials: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + // Set the server certificate and key files. These can be PEM + // files, or PKCS#11 URLs in case an HSM is in use. + ret = + gnutls_certificate_set_x509_key_file(cred, certfile, keyfile, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "error: gnutls_certificate_set_x509_key_file: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (ocspfile) { + ret = gnutls_certificate_set_ocsp_status_request_file(cred, ocspfile, 0); + if (ret < 0) { + fprintf(stderr, + "error: gnutls_certificate_set_ocsp_status_request_file: %s\n", + gnutls_strerror(ret)); + exit(1); + } + } + //- + //+ Features TLS-Server-GNUTLS-Priorities + // Create the ciphersuite priorities object + gnutls_priority_t priority_cache; + const char *errpos = NULL; + + ret = gnutls_priority_init(&priority_cache, "PERFORMANCE:%SERVER_PRECEDENCE", &errpos); + if (ret == GNUTLS_E_PARSING_ERROR) { + fprintf(stderr, "error: gnutls_priority_init parsing error at: %s\n", errpos); + exit(1); + } else if (ret < 0) { + fprintf(stderr, "error: gnutls_priority_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + //- + + const int port = atoi(argv[1]); + struct sockaddr_in sa_serv; + struct sockaddr_storage sa_cli; + socklen_t sa_cli_len; + int sockfd, listenfd; + + listenfd = 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); + + if (bind(listenfd, (struct sockaddr *)&sa_serv, sizeof(sa_serv)) < 0) { + perror("bind"); + exit(1); + } + //+ Features TLS-Server-GNUTLS-Accept + // Create the session object. + for (;;) { + gnutls_session_t session; + + sa_cli_len = sizeof(sa_cli); + sockfd = accept(listenfd, (struct sockaddr *) &sa_cli, &sa_cli_len); + + ret = gnutls_init(&session, GNUTLS_SERVER); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + // Set the acceptable ciphersuites + ret = gnutls_priority_set(session, priority_cache); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_priority_set: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + // Set the server's certificate object + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_credentials_set: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_certificate_server_set_request(session, GNUTLS_CERT_IGNORE); + + gnutls_transport_set_int(session, sockfd); + + // Establish the session. + ret = gnutls_handshake(session); + if (ret != GNUTLS_E_SUCCESS) { + fprintf(stderr, "error: gnutls_handshake: %s\n", gnutls_strerror(ret)); + exit(1); + } + //- + + //+ Features TLS-Server-GNUTLS-Disconnect + // Initiate an orderly connection shutdown. + ret = gnutls_bye(session, GNUTLS_SHUT_WR); + if (ret < 0) { + fprintf(stderr, "error: gnutls_bye: %s\n", gnutls_strerror(ret)); + exit(1); + } + // Free the session object. + gnutls_deinit(session); + //- + close(sockfd); + } + //+ Features TLS-Server-GNUTLS-Credentials-Close + gnutls_priority_deinit(priority_cache); + gnutls_certificate_free_credentials(cred); + //- +} diff --git a/src/src.mk b/src/src.mk index 18bd592..f556eea 100644 --- a/src/src.mk +++ b/src/src.mk @@ -34,8 +34,9 @@ JCFLAGS_TLSClientOpenJDK = -source 1.6 -target 1.6 compile_and_link += C-String-Functions compile_and_link += TLS-Client-OpenSSL LIBS_TLS-Client-OpenSSL = -lssl -lcrypto -compile_and_link += TLS-Client-GNUTLS +compile_and_link += TLS-Client-GNUTLS TLS-Server-GNUTLS LIBS_TLS-Client-GNUTLS = -lgnutls +LIBS_TLS-Server-GNUTLS = -lgnutls compile_and_link += TLS-Client-NSS CFLAGS_TLS-Client-NSS = -I/usr/include/nspr4 -I/usr/include/nss3 LIBS_TLS-Client-NSS = -lnss3 -lnspr4 -lssl3