From b9bb98cf49c24b94a66d38630661b3249ac8ae19 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Mon, 31 Aug 2020 11:07:34 +0200 Subject: [PATCH 1/2] nss: add option to use p11-kit This commit adds an option to replace libnssckbi with the p11-kit-trust[1] module. It makes all NSS application (like Firefox, Chromium, etc.) use the system trust store (/etc/ssl/certs/ in NixOS) and other PKCS#11 modules without ad-hoc configuration. This approach was first implemented in Fedora[2] and other distributions like Arch Linux, later. [1]: https://p11-glue.github.io/p11-glue/p11-kit/manual/trust-nss.html [2]: https://fedoraproject.org/wiki/Features/SharedSystemCertificates --- pkgs/development/libraries/nss/default.nix | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkgs/development/libraries/nss/default.nix b/pkgs/development/libraries/nss/default.nix index 8c98d7ae9bbd..aa691092f85c 100644 --- a/pkgs/development/libraries/nss/default.nix +++ b/pkgs/development/libraries/nss/default.nix @@ -1,4 +1,7 @@ -{ lib, stdenv, fetchurl, nspr, perl, zlib, sqlite, darwin, fixDarwinDylibNames, buildPackages, ninja +{ lib, stdenv, fetchurl, nspr, perl, zlib +, sqlite, ninja +, darwin, fixDarwinDylibNames, buildPackages +, useP11kit ? true, p11-kit , # allow FIPS mode. Note that this makes the output non-reproducible. # https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/NSS_Tech_Notes/nss_tech_note6 enableFIPS ? false @@ -139,6 +142,11 @@ in stdenv.mkDerivation rec { chmod 0755 $out/bin/nss-config ''; + postInstall = stdenv.lib.optionalString useP11kit '' + # Replace built-in trust with p11-kit connection + ln -sf ${p11-kit}/lib/pkcs11/p11-kit-trust.so $out/lib/libnssckbi.so + ''; + postFixup = let isCross = stdenv.hostPlatform != stdenv.buildPlatform; nss = if isCross then buildPackages.nss.tools else "$out"; From cc8a4227c1bf3638a7997cd5772b2d08ef2d903b Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Sun, 10 Jan 2021 18:28:29 +0100 Subject: [PATCH 2/2] nixos/tests/custom-ca: init This is a NixOS test for the security.pki options. --- nixos/tests/all-tests.nix | 1 + nixos/tests/custom-ca.nix | 161 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 nixos/tests/custom-ca.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 523d3c051e04..c7b21432b58c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -81,6 +81,7 @@ in corerad = handleTest ./corerad.nix {}; couchdb = handleTest ./couchdb.nix {}; cri-o = handleTestOn ["x86_64-linux"] ./cri-o.nix {}; + custom-ca = handleTest ./custom-ca.nix {}; deluge = handleTest ./deluge.nix {}; dhparams = handleTest ./dhparams.nix {}; dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {}; diff --git a/nixos/tests/custom-ca.nix b/nixos/tests/custom-ca.nix new file mode 100644 index 000000000000..67f7b3ff1f16 --- /dev/null +++ b/nixos/tests/custom-ca.nix @@ -0,0 +1,161 @@ +# Checks that `security.pki` options are working in curl and the main browser +# engines: Gecko (via Firefox), Chromium, QtWebEngine (Falkon) and WebKitGTK +# (via Midori). The test checks that certificates issued by a custom trusted +# CA are accepted but those from an unknown CA are rejected. + +import ./make-test-python.nix ({ pkgs, lib, ... }: + +let + makeCert = { caName, domain }: pkgs.runCommand "example-cert" + { buildInputs = [ pkgs.gnutls ]; } + '' + mkdir $out + + # CA cert template + cat >ca.template <server.template < Tuple[int, str]: + """ + Run a shell command as a specific user. + """ + return machine.execute(f"sudo -u {user} {cmd}") + + + def wait_for_window_as(user: str, cls: str) -> None: + """ + Wait until a X11 window of a given user appears. + """ + + def window_is_visible(last_try: bool) -> bool: + ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}") + if last_try: + machine.log(f"Last chance to match {cls} on the window list") + return ret == 0 + + with machine.nested("Waiting for a window to appear"): + retry(window_is_visible) + + + machine.start() + + with subtest("Good certificate is trusted in curl"): + machine.wait_for_unit("nginx") + machine.wait_for_open_port(443) + machine.succeed("curl -fv https://good.example.com") + + with subtest("Unknown CA is untrusted in curl"): + machine.fail("curl -fv https://bad.example.com") + + browsers = ["firefox", "chromium", "falkon", "midori"] + errors = ["Security Risk", "not private", "Certificate Error", "Security"] + + machine.wait_for_x() + for browser, error in zip(browsers, errors): + with subtest("Good certificate is trusted in " + browser): + execute_as( + "alice", f"env P11_KIT_DEBUG=trust {browser} https://good.example.com & >&2" + ) + wait_for_window_as("alice", browser) + machine.wait_for_text("It works!") + machine.screenshot("good" + browser) + execute_as("alice", "xdotool key ctrl+w") # close tab + + with subtest("Unknown CA is untrusted in " + browser): + execute_as("alice", f"{browser} https://bad.example.com & >&2") + machine.wait_for_text(error) + machine.screenshot("bad" + browser) + machine.succeed("pkill " + browser) + ''; +})