<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:lighttpd.net:lighttpd2/doc1">
	<short>listens on separate sockets for TLS connections (https) using GnuTLS</short>

	<setup name="gnutls">
		<short>setup a TLS socket</short>
		<parameter name="options">
			<table>
				<entry name="listen">
					<short>(mandatory) the socket address to listen on (same as "listen":plugin_core.html#plugin_core__setup_listen), can be specified more than once to setup multiple sockets with the same options</short>
				</entry>
				<entry name="pemfile">
					<short>(mandatory) file containing the private key, certificate, intermediate certificates (the root certificate is usually not
					included) and an OCSP response; alternatively it can be a key-value list with a "key" and a "cert" entry, and optionally a "ocsp" entry.</short>
				</entry>
				<entry name="pin">
					<short>the PIN (or password) to use when using PKCS #11 modules or encrypted keys. The pin is kept in memory.</short>
				</entry>
				<entry name="priority">
					<short>GnuTLS priority string, specifying ciphers and other GnuTLS options (default: "NORMAL")</short>
				</entry>
				<entry name="dh-params">
					<short>filename with generated dh-params (default: fixed 4096-bit parameters)</short>
				</entry>
				<entry name="protect-against-beast">
					<short>whether to force RC4 on TLS1.0 and SSL3.0 connections by appending ":-CIPHER-ALL:+ARCFOUR-128" to the priority string (default: false)</short>
				</entry>
				<entry name="session-db-size">
					<short>size of session database, 0 to disable session support (TLS ticket support is always enabled if GnuTLS supports it)</short>
				</entry>
				<entry name="sni-backend">
					<short>"fetch" backend name to search certificates in with the SNI servername as key (only available if SNI in lighttpd2 was enabled)</short>
				</entry>
				<entry name="sni-fallback-pemfile">
					<short>certificate to use if request contained SNI servername, but the sni-backend didn't find anything; if request didn't contain SNI the standard "pemfile"(s) are used; similarly with "pemfile" it can also be a key-value list with a "key" and a "cert" entry.</short>
				</entry>
			</table>
		</parameter>

		<example title="Simple TLS on IPv4 and IPv6">
			<config>
				setup {
					module_load "mod_gnutls";
					gnutls (
						"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
						"listen" => "0.0.0.0:443",
						"listen" => "[::]:443",
						"pemfile" => "/etc/certs/lighttpd.pem"
					);
				}
			</config>
		</example>

		<example title="TLS with simple SNI">
			<config>
				setup {
					module_load "mod_gnutls";
					gnutls (
						"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
						"listen" => "0.0.0.0:443",
						"listen" => "[::]:443",
						"pemfile" => "/etc/certs/www.example.com.pem"
						"pemfile" => "/etc/certs/mail.example.com.pem"
					);
				}
			</config>
		</example>

		<example title="TLS with SNI from fetch backend">
			<description><markdown>
				For a SNI hostname `example.com` lighttpd2 will try to find the private key and certificate(s) in `/etc/certs/lighttpd_sni_example.com.pem`.
			</markdown></description>
			<config>
				setup {
					fetch.files_static "sni" => "/etc/certs/lighttpd_sni_*.pem";

					module_load "mod_gnutls";
					gnutls (
						"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
						"sni-backend" => "sni",
						"listen" => "0.0.0.0:443",
						"listen" => "[::]:443",
						"pemfile" => "/etc/certs/lighttpd.pem"
					);
				}
			</config>
		</example>

		<example title="Simple TLS on IPv4 and IPv6 with separate files for key and certificate and encrypted key">
			<config>
				setup {
					module_load "mod_gnutls";
					gnutls (
						"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
						"listen" => "0.0.0.0:443",
						"listen" => "[::]:443",
						"pin" => "passwordForEncryptedKey",
						"pemfile" => (
							"key" => "/etc/certs/lighttpd_key.pem",
							"cert" => "/etc/certs/lighttpd_cert.pem"
						)
					);
				}
			</config>
		</example>

		<example title="Simple TLS on IPv4 and IPv6 with SoftHSM">
			<config>
				setup {
					module_load "mod_gnutls";
					gnutls (
						"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
						"listen" => "0.0.0.0:443",
						"listen" => "[::]:443",
						"pin" => "SoftHSM-pin",
						"pemfile" => (
							"key" => "pkcs11:model=SoftHSM;manufacturer=SoftHSM;serial=1;token=master-key;id=%ac%d5%52%69%16%09%2c%0c%9c%b0%ec%6c%3d%3b%c6%4d%55%4c%40%49;object=my-key;object-type=private",
							"cert" => "pkcs11:model=SoftHSM;manufacturer=SoftHSM;serial=1;token=master-key;id=%ac%d5%52%69%16%09%2c%0c%9c%b0%ec%6c%3d%3b%c6%4d%55%4c%40%49;object=my-key;object-type=cert"
						)
					);
				}
			</config>
		</example>

		<example title="Simple TLS on IPv4 and IPv6 with OCSP stapling">
			<config>
				setup {
					module_load "mod_gnutls";
					gnutls (
						"priority" => "PFS:-3DES-CBC:-ARCFOUR-128:-VERS-SSL3.0:-SHA1:+SHA1:+RSA:%SERVER_PRECEDENCE",
						"listen" => "0.0.0.0:443",
						"listen" => "[::]:443",
						"pemfile" => (
							"key" => "/etc/certs/lighttpd.pem",
							"cert" => "/etc/certs/lighttpd.pem",
							"ocsp" => "/etc/certs/lighttpd-ocsp.der",
						)
					);
				}
			</config>
		</example>
	</setup>

	<section title="Server Name Indication (SNI)">
		<markdown>
			[TLS SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) means that a client can send the hostname of the server it tries to connect to **unencrypted** in the TLS handshake.  
			If you want to host multiple hostnames on the same IP address (quite common) there are some options how to do it (they can be combined):

			* Use a wildcard as "CommonName" (CN) in the certificate like `*.example.com` (although this usually doesn't match `example.com`)
			* Use "Subject Alternative Names" in the certificate
			* Provide different certificates based on the SNI hostname in the TLS handshake.

			Clients supporting SNI usually support the other options too, but not all clients support SNI.

			GnuTLS has some basic SNI support built in; if you specify multiple `pemfile` s in the options, it will pick the first with a certificate that matches the SNI hostname.

			lighttpd2 has an optional extended SNI support (which has to be enabled at compile time, and is required for the `sni-*` options to be available). It is designed to load certificates asynchronously from backends (files, SQL, ...) on demand, using the [fetch API](core_fetch.html#core_fetch).  
			In this case lighttpd2 will fetch the certificate based on the SNI hostname from the given `sni-backend` before GnuTLS is started for a connection.  
			If a SNI hostname was given by the client, but no certificate was found in the backend, it will use `sni-fallback-pemfile` (if set) instead of `pemfile`.

			Combining `sni-backend`, `sni-fallback-pemfile` and multiple `pemfile` s won't work - it will only use the first configured `pemfile` (if no SNI hostname was given by the client, otherwise `sni-*` certificates are used).

			Also note that lighttpd2 does NOT verify whether the SNI hostname matches the hostname in the HTTP request. SNI is only used by the client to tell the server for which hostname it should send the certificate (i.e. what the client is using to verify it).
		</markdown>
	</section>

	<section title="GnuTLS priority string">
		<markdown>
			The GnuTLS priority string configures which ciphers and protocol versions are available, and also a small set of options (workarounds to activate and so on).

			Example: `"SECURE:-VERS-SSL3.0:-SHA1:+SHA1:-RSA:+RSA:%SERVER_PRECEDENCE"`

			* `SECURE`: starts with `SECURE` level: only secure ciphers and secure curves
			* `-VERS-SSL3.0`: disables SSL3.0 support (all clients should support at least TLS1.0 now)
			* `-SHA1:SHA1` puts SHA1 back at the list for MAC algorithms (preferring the other SHA variants)
			* `-RSA:+RSA`: prefer (RSA) DHE/ECDHE key exchanges over simple RSA
			* `%SERVER_PRECEDENCE` a flag telling GnuTLS to use its own order of preference instead of the order provided by the client.

			See also:

			* [Priority strings](https://gnutls.org/manual/html_node/Priority-Strings.html#Priority-Strings) (GnuTLS manual)
			* [GnuTLS Priority Strings](https://blog.lighttpd.net/gnutls-priority-strings.html)
			* `gnutls-cli -l --priority "SECURE:-VERS-SSL3.0:-SHA1:+SHA1:-RSA:+RSA:%SERVER_PRECEDENCE"`
		</markdown>
	</section>

	<section title="OCSP stapling">
		<markdown>
			[OCSP stapling](https://en.wikipedia.org/wiki/OCSP_stapling) is used to assure a client the certificate is still valid (i.e. not revoked); you can put an OCSP response into the certificate file in an "OCSP RESPONSE"-PEM block (there is probably no standard for this, just base64-encode the DER-response you have), or specify the (DER or PEM formatted) OCSP response as separate file using "ocsp" in a "pemfile" block.

			Server Name Indication (SNI) should work fine, as an OCSP response is only used if it matches the certificate in use for the connection.

			The fetch backends do support OCSP stapling if the OCSP response is appended as PEM block.

			Lighttpd does NOT automatically reload OCSP responses; you have to restart to load new OCSP responses (a cron job is probably the right way to do it).

			If you have your certificate and the issuer-certificate (the one that signed yours) in separate files you can request an OCSP response like that (using the GnuTLS "ocsptool"):

				ocsptool --ask --load-issuer issuer.pem --load-cert cert.pem --outfile ocsp.der

			Converting into PEM format can be done like this:

				(echo "-----BEGIN OCSP RESPONSE-----"; base64 --wrap=64 ocsp.der; echo "-----END OCSP RESPONSE-----") > ocsp.pem

			If you have trouble identifying which certificates you need, here the more detailed explanation:

			You usually have a list of certificates in the PEM file you pass to lighttpd. The first certificate usually has a "Subject" pointing to your server name (CN), like: "Subject: CN=lighttpd.net". It also has a "Issuer" attribute (like "C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3"). The issuer certificate needs a "Subject" matching that "Issuer", and should be the second certificate in the PEM file (unless it already is the root CA, in which case it is usually omitted).

			`ocsptool` will always use the first certificate in a file and ignore the others, so you can use the normal PEM file you pass to lighttpd as argument after `--load-cert`, but you need to extract the issuer certificate if you don't have it in a separate file. The following `awk` script extracts the second PEM block from a file:

				awk '
					BEGIN { block = 0 }
					/^-----BEGIN / { ++block; }
					{ if (block > 1) print; }
				' "certs.pem" > "issuer.pem"
		</markdown>
	</section>

	<section title="protect-against-beast">
		<markdown>
			[BEAST](https://en.wikipedia.org/wiki/Transport_Layer_Security#BEAST_attack) is considered mitigated on clients by many now, so this workaround is no longer recommended and disabled by default.

			It enabled it will enforce the usage of RC4 on TLS1.0 and before (TLS1.1 and TLS1.2 are not vulnerable); but RC4 has issues on its own.
		</markdown>
	</section>

	<section title="DH parameters">
		<markdown>
			The `DHE_RSA` key exchange requires parameters (similar to the curves used for `ECDHE_RSA`); the parameters specify a prime `p` and a group generator `g` of the multiplicative group of integers modulo `p` (i.e. for all `x` in `1..p-1` exists an `e` with `g^e = x`); sometimes `g` might only create a sufficiently large subgroup (for example of size `(p-1)/2`).

			The security of the DH key exchange depends (among other things) on the bit length of `p`; therefore lighttpd includes default 4096-bit parameters (provided by the GnuTLS certtool with `certtool --get-dh-params --bits=4096` in version 3.0.22), and these should be safe to use (key lengths > 1024 are not supported by some older clients; if you need to support those you either have to disable DH key exchange or specify 1024-bit parameters).

			You can use either GnuTLS or openssl to generate your own parameters:

			* `certtool --generate-dh-params --bits=2048`
			* `openssl dhparam -dsaparam 2048`
			* `openssl dhparam -2 2048`
			* `openssl dhparam -5 2048`

			The GnuTLS `certtool` only generates "DSA" parameters (any prime with a large generator), while `openssl` can generate "DH" parameters with a generator of 2 or 5 combined with a Sophie Germain prime `(p-1)/2` (i.e. both `p` and `(p-1)/2` are primes) or "DSA" parameters using the `-dsaparam` option.

			"DH" parameters take a lot more time to generate, but you can reuse keys for those (although it is not recommended, search for `SSL_OP_SINGLE_DH_USE` in the openssl manual on `SSL_CTX_set_tmp_dh_callback`). Keys for "DSA" parameters should not be reused, i.e. one should generate a new private key for each connection, which is the case in mod_gnutls. The default parameters provided by lighttpd are "DH" parameters.

			See also:

			* [Diffie-Hellman(-Merkle) key exchange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange)
			* [OpenSSL: Documents, dhparam(1)](https://www.openssl.org/docs/apps/dhparam.html)
			* [OpenSSL: Documents, SSL_CTX_set_tmp_dh_callback(3)](https://www.openssl.org/docs/ssl/SSL_CTX_set_tmp_dh_callback.html#NOTES)
		</markdown>
	</section>
</module>
