(network-security-services-nss)= # Network Security Services (NSS) Network Security Services, or NSS, is a set of libraries that was originally developed by Netscape and later inherited by Mozilla. In Ubuntu, it's used mainly in Mozilla products such as Firefox and Thunderbird, but there are modules and language bindings available for other packages to use. Given its origins in the Netscape browser, this library used to be bundled together with the applications that required it. Up to this day, for example, the Debian package of Mozilla Thunderbird has its own copy of `libnss3`, ignoring the system-wide one shipped by the `libnss3` Debian package. ## Config file NSS doesn't have a system-wide policy configuration file in Ubuntu ([see #2016303](https://bugs.launchpad.net/ubuntu/+source/nss/+bug/2016303) for details). That leaves the remaining location for the configuration file to be in the NSS "database" directory. Depending on the application, it can be in the following places by default: - `~/.pki/nssdb/pkcs11.txt` This is where the system-provided `libnss3` library will look by default. - `~/snap/firefox/common/.mozilla/firefox/.default/pkcs11.txt` This is where the Firefox snap will look. - `~/.thunderbird/.default-release/pkcs11.txt` Mozilla Thunderbird ships with its own copy of `libnss3`, and is configured to look into this directory to find it. - `~/.netscape/pkcs11.txt` This is the default used by the NSS tools shipped in the `libnss3-tools` Debian package. The directory where `pkcs11.txt` is looked up is also the NSS database directory. NSS will store the certificates and private keys it imports or generates here, and the directory will typically contain these SQLITE3 database files: - `cert9.db`: certificates database - `key4.db`: private key database With the `pkcs11.txt` file we can load PKCS#11 modules, including the one built into NSS itself. Other examples of modules that can be loaded from there are modules for smart cards or other hardware-based cryptographic devices. Of interest to us here, though, is the policy module. ## Configuring the NSS policy module The policy module is defined like this in `pkcs11.txt`: ```text library= name=Policy NSS=flags=policyOnly,moduleDB config="disallow= allow= flags=" ``` It's via the `config=` line that we can list which cryptographic algorithms we want to allow and disallow. The terms in the list are separated with a colon ("`:`") and consist of the following: - **The special keyword "ALL"**, meaning all possible values and algorithms. It's mostly used with `disallow`, so that a clean slate can be constructed with a following `allow` list. For example, `disallow=ALL allow=` would only allow the algorithms explicitly listed in the `allow` list. - **Algorithm name**: Standard names like `sha256`, `hmac-sha256`, `chacha20-poly1305`, `aes128-gcm` and others. - **Version specifiers**: A minimum or maximum version for a protocol. These are the available ones: - `tls-version-min`, `tls-version-max`: Minimum and maximum version for the TLS protocol. For example, `tls-version-min=tls1.2`. - `dtls-version-min`, `dtls-version-max`: As above, but for DTLS (TLS over UDP) - **Key sizes**: Minimum size for a key: - `DH-MIN`: Diffie-Helman minimum key size. For example, `DH-MIN=2048` specifies a minimum of 2048 bits. - `DSA-MIN`: Digital Signature Algorithm minimum key size. For example, `DSA-MIN=2048` specifies a minimum of 2048 bits. - `RSA-MIN`: RSA minimum key size. For example, `RSA-MIN=2048` specifies a minimum of 2048 bits. - **Signature qualifier**: Selects the specified algorithm with a specific type of signature. For example, `sha256/cert-signature`. Here are some of the qualifiers that are available: - `/cert-signature`: Used in certificate signatures, certificate revocation lists (CRLs) and Online Certificate Status Protocol (OCSP). - `/signature`: Used in any signature. - `/all`: Combines SSL, SSL key exchange, and signatures. - `/ssl-key-exchange`: Used in the SSL key exchange. - `/ssl`: Used in the SSL record protocol. The `disallow` rules are always parsed first, and then the `allow` ones, independent of the order in which they appear. There are extra flags that can be added to the `config` line as well, in a comma-separated list if more than one is specified: - `policy-lock`: Turn off the ability for applications to change policy with API calls. - `ssl-lock`: Turn off the ability to change the SSL defaults. ## Practical examples Let's see some practical examples of how we can use the configuration file to tweak the default cryptographic settings of an application linked with the system NSS libraries. For these examples, we will be using the configuration file located in `~/.pki/nssdb/pkcs11.txt`. As noted before, depending on the application this file can be in another directory. The examples will use the `tstclnt` test application that is part of the `libnss3-tools` Debian package. For the server part, we will be using the OpenSSL test server on the same system. Since it uses the OpenSSL library, it won't be affected by the changes we make to the NSS configuration. ### Bootstrapping the NSS database Install the `libnss3-tools` package which has the necessary tools we will need: ```bash sudo apt install libnss3-tools ``` If you don't have a `~/.pki/nssdb` directory yet, it will have to be created first. For that, we will use the `certutil` command, also part of the `libnss3-tools` package. This will bootstrap the NSS database in that directory, and also create the initial `pkcs11.txt` file we will tweak in the subsequent examples: ```bash mkdir -p ~/.pki/nssdb certutil -d ~/.pki/nssdb -N ``` If you already have a populated `~/.pki/nssdb` directory, there is no need to run the above commands. When running the `certutil` command as shown, you will be asked to choose a password. That password will protect the NSS database, and will be requested whenever certain changes are made to it. In the following examples we will make changes to the `pkcs11.txt` file inside the NSS database directory. The bootstrap process above will have created this file for us already. The changes that we will make should be *added* to the file, and not replace it. For example, these are the contents of `~/.pki/nssdb/pkcs11.txt` right after the bootstrap process: ```text library= name=NSS Internal PKCS #11 Module parameters=configdir='/home/ubuntu/.pki/nssdb' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription='' NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30}) ``` When an example asks to configure the policy module, its block should be appended to the existing configuration block in the file. For example: ```text library= name=NSS Internal PKCS #11 Module parameters=configdir='/home/ubuntu/.pki/nssdb' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription='' NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30}) library= name=Policy NSS=flags=policyOnly,moduleDB config="allow=tls-version-min=tls1.3" ``` ### Test setup For these examples, we will be using a simple OpenSSL server on the same system as the NSS client we are testing. For that we will have to generate a certificate and key for the OpenSSL server to use, and then import that into the NSS database so it can be trusted. First, generate a keypair for OpenSSL: ```bash openssl req -new -x509 -days 30 -nodes -subj "/CN=localhost" -out localhost.pem -keyout localhost.key ``` To avoid telling `tstclnt` to ignore certification validation errors, which might mask the crypto policy changes we are trying to demonstrate, it's best to import this certificate into the NSS database and mark it as trusted: ```bash certutil -d ~/.pki/nssdb -A -a -i localhost.pem -t TCP -n localhost ``` This command will ask you for the NSS database password that you supplied when bootstrapping it. The command line options that were used have the following meanings: * `-d ~/.pki/nssdb`: The path to the NSS database. * `-A`: Import a certificate. * `-a`: The certificate is in ASCII mode (PEM). * `-i localhost.pem`: The file to read (the actual certificate). * `-t TCP`: Trust flags (see the `-t trustargs` argument in the [certutil manpage](https://manpages.ubuntu.com/manpages/jammy/en/man1/certutil.1.html) for a full list). * `T`: Trusted CA for client authentication. * `C`: Trusted CA. * `P`: Trusted peer. * `-n localhost`: A nickname for this certificate, like a label. It can be used later on to select this certificate. We are now ready to begin our tests. Unless otherwise noted, this is how it's expected that the server will be run: ```bash openssl s_server -accept 4443 -cert localhost.pem -key localhost.key -www ``` ### The `tstclnt` tool The `libnss3-tools` package also contains the `tstclnt` tool, which is what we will use in the following examples to test our NSS configuration changes. This is the typical command we will use: ```bash tstclnt -d ~/.pki/nssdb -h localhost -p 4443 ``` Where the options have the following meanings: * `-d ~/.pki/nssdb`: Use the NSS database located in the `~/.pki/nssdb` directory. * `-h localhost`: The server to connect to. * `-p 4443`: The TCP port to connect to. To make things a bit easier to see, since this tool prints a lot of information about the connection, we will wrap it like this: ```bash echo "GET / HTTP/1.0" | tstclnt -d ~/.pki/nssdb -h localhost -p 4443 2>&1 | grep ^New New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256 ^C ``` The above tells us that the connection was completed and that it is using `TLSv1.3`, with a `TLS_AES_128_GCM_SHA256` cipher suite. It will not exit on its own, so it's necessary to press Ctrl+C (`^C`) to get back to the shell prompt. ### Only use TLSv1.3 Here is how we can restrict the TLS protocol version to 1.3 at a minimum: ```text library= name=Policy NSS=flags=policyOnly,moduleDB config="allow=tls-version-min=tls1.3" ``` If we then start the OpenSSL server without TLSv1.3 support, like this (note the extra `no_tls1_3` at the end): ```bash openssl s_server -accept 4443 -cert localhost.pem -key localhost.key -www -no_tls1_3 ``` The `tstclnt` tool will fail to connect: ```bash echo "GET / HTTP/1.0" | tstclnt -d ~/.pki/nssdb -h localhost -p 4443 2>&1 | grep ^New echo $? 1 ``` To see the actual error, we can remove the `grep` at the end: ```bash echo "GET / HTTP/1.0" | tstclnt -d ~/.pki/nssdb -h localhost -p 4443 2>&1 tstclnt: write to SSL socket failed: SSL_ERROR_PROTOCOL_VERSION_ALERT: Peer reports incompatible or unsupported protocol version. ``` If we allow the server to offer TLSv1.3: ```bash openssl s_server -accept 4443 -cert localhost.pem -key localhost.key -www ``` Then the connection completes: ```bash echo "GET / HTTP/1.0" | tstclnt -d ~/.pki/nssdb -h localhost -p 4443 2>&1 | grep ^New New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256 ^C ``` ### Use only AES256 with TLSv1.3 In the previous example, the connection ended up using TLSv1.3 as expected, but AES128. To enforce AES256, we can disallow the 128-bit version: ```text library= name=Policy NSS=flags=policyOnly,moduleDB config="disallow=aes128-gcm allow=tls-version-min=tls1.3" ``` This time the client selects something else: ```bash echo "GET / HTTP/1.0" | tstclnt -d ~/.pki/nssdb -h localhost -p 4443 2>&1 | grep ^New New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256 ``` We can remove that one from the list as well: ```text config="disallow=aes128-gcm:chacha20-poly1305 allow=tls-version-min=tls1.3" ``` And now we get AES256: ```bash echo "GET / HTTP/1.0" | tstclnt -d ~/.pki/nssdb -h localhost -p 4443 2>&1 | grep ^New New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 ``` ## References Unfortunately most of the upstream Mozilla documentation is either outdated or deprecated, and the best reference available about the policy module at the moment is in the source code and tests. * [In the source code](https://git.launchpad.net/ubuntu/+source/nss/tree/nss/lib/pk11wrap/pk11pars.c#n144) * [In the tests (policy)](https://git.launchpad.net/ubuntu/+source/nss/tree/nss/tests/policy) * [In the tests (SSL policy)](https://git.launchpad.net/ubuntu/+source/nss/tree/nss/tests/ssl/sslpolicy.txt)