forked from mirrors/nixpkgs
cacert: port to use buildcatrust
This introduces the ability to have additional certificates in the trust store using an override, similar to how the blacklist is done. If the certificates are provided in OpenSSL TRUSTED CERTIFICATE form, then those trust bits will be respected. It also adds a p11-kit compatible trust store output.
This commit is contained in:
parent
44c4fd09a1
commit
906f44cef3
|
@ -1,27 +1,23 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, writeText
|
||||
, fetchurl
|
||||
, nss
|
||||
, python3
|
||||
, blacklist ? [ ]
|
||||
, buildcatrust
|
||||
, blacklist ? []
|
||||
, extraCertificateFiles ? []
|
||||
, extraCertificateStrings ? []
|
||||
|
||||
# Used for tests only
|
||||
# Used for tests only
|
||||
, runCommand
|
||||
, cacert
|
||||
, openssl
|
||||
}:
|
||||
|
||||
let
|
||||
certdata2pem = fetchurl {
|
||||
name = "certdata2pem.py";
|
||||
urls = [
|
||||
"https://salsa.debian.org/debian/ca-certificates/raw/debian/20170717/mozilla/certdata2pem.py"
|
||||
"https://git.launchpad.net/ubuntu/+source/ca-certificates/plain/mozilla/certdata2pem.py?id=47e49e1e0a8a1ca74deda27f88fe181191562957"
|
||||
];
|
||||
sha256 = "1d4q27j1gss0186a5m8bs5dk786w07ccyq0qi6xmd2zr1a8q16wy";
|
||||
};
|
||||
blocklist = writeText "cacert-blocklist.txt" (lib.concatStringsSep "\n" blacklist);
|
||||
extraCertificatesBundle = writeText "cacert-extra-certificates-bundle.crt" (lib.concatStringsSep "\n\n" extraCertificateStrings);
|
||||
in
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "nss-cacert";
|
||||
version = "3.71";
|
||||
|
@ -31,93 +27,152 @@ stdenv.mkDerivation rec {
|
|||
sha256 = "0ly2l3dv6z5hlxs72h5x6796ni3x1bq60saavaf42ddgv4ax7b4r";
|
||||
};
|
||||
|
||||
outputs = [ "out" "unbundled" ];
|
||||
outputs = [ "out" "unbundled" "p11kit" ];
|
||||
|
||||
nativeBuildInputs = [ python3 ];
|
||||
nativeBuildInputs = [ buildcatrust ];
|
||||
|
||||
configurePhase = ''
|
||||
ln -s nss/lib/ckfw/builtins/certdata.txt
|
||||
|
||||
cat << EOF > blacklist.txt
|
||||
${lib.concatStringsSep "\n" (map (c: ''"${c}"'') blacklist)}
|
||||
EOF
|
||||
|
||||
# copy from the store, otherwise python will scan it for imports
|
||||
cat "${certdata2pem}" > certdata2pem.py
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
python certdata2pem.py | grep -vE '^(!|UNTRUSTED)'
|
||||
|
||||
for cert in *.crt; do
|
||||
echo $cert | cut -d. -f1 | sed -e 's,_, ,g' >> ca-bundle.crt
|
||||
cat $cert >> ca-bundle.crt
|
||||
echo >> ca-bundle.crt
|
||||
done
|
||||
mkdir unbundled
|
||||
buildcatrust \
|
||||
--certdata_input certdata.txt \
|
||||
--ca_bundle_input "${extraCertificatesBundle}" ${lib.escapeShellArgs (map (arg: "${arg}") extraCertificateFiles)} \
|
||||
--blocklist "${blocklist}" \
|
||||
--ca_bundle_output ca-bundle.crt \
|
||||
--ca_unpacked_output unbundled \
|
||||
--p11kit_output ca-bundle.trust.p11-kit
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -pv $out/etc/ssl/certs
|
||||
cp -v ca-bundle.crt $out/etc/ssl/certs
|
||||
install -D -t "$out/etc/ssl/certs" ca-bundle.crt
|
||||
|
||||
# install p11-kit specific output to p11kit output
|
||||
install -D -t "$p11kit/etc/ssl/trust-source" ca-bundle.trust.p11-kit
|
||||
|
||||
# install individual certs in unbundled output
|
||||
mkdir -pv $unbundled/etc/ssl/certs
|
||||
cp -v *.crt $unbundled/etc/ssl/certs
|
||||
rm $unbundled/etc/ssl/certs/ca-bundle.crt # not wanted in unbundled
|
||||
install -D -t "$unbundled/etc/ssl/certs" unbundled/*.crt
|
||||
'';
|
||||
|
||||
setupHook = ./setup-hook.sh;
|
||||
|
||||
passthru = {
|
||||
updateScript = ./update.sh;
|
||||
tests = {
|
||||
# Test that building this derivation with a blacklist works, and that UTF-8 is supported.
|
||||
blacklist-utf8 =
|
||||
let
|
||||
blacklistCAToFingerprint = {
|
||||
# "blacklist" uses the CA name from the NSS bundle, but we check for presence using the SHA256 fingerprint.
|
||||
"CFCA EV ROOT" = "5C:C3:D7:8E:4E:1D:5E:45:54:7A:04:E6:87:3E:64:F9:0C:F9:53:6D:1C:CC:2E:F8:00:F3:55:C4:C5:FD:70:FD";
|
||||
"NetLock Arany (Class Gold) Főtanúsítvány" = "6C:61:DA:C3:A2:DE:F0:31:50:6B:E0:36:D2:A6:FE:40:19:94:FB:D1:3D:F9:C8:D4:66:59:92:74:C4:46:EC:98";
|
||||
};
|
||||
mapBlacklist = f: lib.concatStringsSep "\n" (lib.mapAttrsToList f blacklistCAToFingerprint);
|
||||
in
|
||||
runCommand "verify-the-cacert-filter-output"
|
||||
{
|
||||
cacert = cacert.unbundled;
|
||||
cacertWithExcludes = (cacert.override {
|
||||
blacklist = builtins.attrNames blacklistCAToFingerprint;
|
||||
}).unbundled;
|
||||
|
||||
nativeBuildInputs = [ openssl ];
|
||||
} ''
|
||||
isPresent() {
|
||||
# isPresent <unbundled-dir> <ca name> <ca sha256 fingerprint>
|
||||
for f in $1/etc/ssl/certs/*.crt; do
|
||||
fingerprint="$(openssl x509 -in "$f" -noout -fingerprint -sha256 | cut -f2 -d=)"
|
||||
if [[ "x$fingerprint" == "x$3" ]]; then
|
||||
return 0
|
||||
tests = let
|
||||
isTrusted = ''
|
||||
isTrusted() {
|
||||
# isTrusted <unbundled-dir> <ca name> <ca sha256 fingerprint>
|
||||
for f in $1/etc/ssl/certs/*.crt; do
|
||||
if ! [[ -s "$f" ]]; then continue; fi
|
||||
fingerprint="$(openssl x509 -in "$f" -noout -fingerprint -sha256 | cut -f2 -d=)"
|
||||
if [[ "x$fingerprint" == "x$3" ]]; then
|
||||
# If the certificate is treated as rejected for TLS Web Server, then we consider it untrusted.
|
||||
if openssl x509 -in "$f" -noout -text | grep -q '^Rejected Uses:'; then
|
||||
if openssl x509 -in "$f" -noout -text | grep -A1 '^Rejected Uses:' | grep -q 'TLS Web Server'; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
'';
|
||||
in {
|
||||
# Test that building this derivation with a blacklist works, and that UTF-8 is supported.
|
||||
blacklist-utf8 = let
|
||||
blacklistCAToFingerprint = {
|
||||
# "blacklist" uses the CA name from the NSS bundle, but we check for presence using the SHA256 fingerprint.
|
||||
"CFCA EV ROOT" = "5C:C3:D7:8E:4E:1D:5E:45:54:7A:04:E6:87:3E:64:F9:0C:F9:53:6D:1C:CC:2E:F8:00:F3:55:C4:C5:FD:70:FD";
|
||||
"NetLock Arany (Class Gold) Főtanúsítvány" = "6C:61:DA:C3:A2:DE:F0:31:50:6B:E0:36:D2:A6:FE:40:19:94:FB:D1:3D:F9:C8:D4:66:59:92:74:C4:46:EC:98";
|
||||
};
|
||||
mapBlacklist = f: lib.concatStringsSep "\n" (lib.mapAttrsToList f blacklistCAToFingerprint);
|
||||
in runCommand "verify-the-cacert-filter-output" {
|
||||
cacert = cacert.unbundled;
|
||||
cacertWithExcludes = (cacert.override {
|
||||
blacklist = builtins.attrNames blacklistCAToFingerprint;
|
||||
}).unbundled;
|
||||
|
||||
# Ensure that each certificate is in the main "cacert".
|
||||
${mapBlacklist (caName: caFingerprint: ''
|
||||
isPresent "$cacert" "${caName}" "${caFingerprint}" || ({
|
||||
echo "CA fingerprint ${caFingerprint} (${caName}) is missing from the CA bundle. Consider picking a different CA for the blacklist test." >&2
|
||||
exit 1
|
||||
})
|
||||
'')}
|
||||
nativeBuildInputs = [ openssl ];
|
||||
} ''
|
||||
${isTrusted}
|
||||
|
||||
# Ensure that each certificate is NOT in the "cacertWithExcludes".
|
||||
${mapBlacklist (caName: caFingerprint: ''
|
||||
isPresent "$cacertWithExcludes" "${caName}" "${caFingerprint}" && ({
|
||||
echo "CA fingerprint ${caFingerprint} (${caName}) is present in the cacertWithExcludes bundle." >&2
|
||||
exit 1
|
||||
})
|
||||
'')}
|
||||
# Ensure that each certificate is in the main "cacert".
|
||||
${mapBlacklist (caName: caFingerprint: ''
|
||||
isTrusted "$cacert" "${caName}" "${caFingerprint}" || ({
|
||||
echo "CA fingerprint ${caFingerprint} (${caName}) is missing from the CA bundle. Consider picking a different CA for the blacklist test." >&2
|
||||
exit 1
|
||||
})
|
||||
'')}
|
||||
|
||||
touch $out
|
||||
# Ensure that each certificate is NOT in the "cacertWithExcludes".
|
||||
${mapBlacklist (caName: caFingerprint: ''
|
||||
isTrusted "$cacertWithExcludes" "${caName}" "${caFingerprint}" && ({
|
||||
echo "CA fingerprint ${caFingerprint} (${caName}) is present in the cacertWithExcludes bundle." >&2
|
||||
exit 1
|
||||
})
|
||||
'')}
|
||||
|
||||
touch "$out"
|
||||
'';
|
||||
|
||||
# Test that we can add additional certificates to the store, and have them be trusted.
|
||||
extra-certificates = let
|
||||
extraCertificateStr = ''
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB5DCCAWqgAwIBAgIUItvsAYEIdYDkOIo5sdDYMcUaNuIwCgYIKoZIzj0EAwIw
|
||||
KTEnMCUGA1UEAwweTml4T1MgY2FjZXJ0IGV4dHJhIGNlcnRpZmljYXRlMB4XDTIx
|
||||
MDYxMjE5MDQzMFoXDTIyMDYxMjE5MDQzMFowKTEnMCUGA1UEAwweTml4T1MgY2Fj
|
||||
ZXJ0IGV4dHJhIGNlcnRpZmljYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEuP8y
|
||||
lAm6ZyQt9v/P6gTlV/a9R+D61WjucW04kaegOhg8csiluimYodiSv0Pbgymu+Zxm
|
||||
A3Bz9QGmytaYTiJ16083rJkwwIhqoYl7kWsLzreSTaLz87KH+rdeol59+H0Oo1Mw
|
||||
UTAdBgNVHQ4EFgQUCxuHfvqI4YVU5M+A0+aKvd1LrdswHwYDVR0jBBgwFoAUCxuH
|
||||
fvqI4YVU5M+A0+aKvd1LrdswDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNo
|
||||
ADBlAjEArgxgjdNmRlSEuai0dzlktmBEDZKy2Iiul+ttSoce9ohfEVYESwO602HW
|
||||
keVvI56vAjBCro3dc3m2TuktiKO6lQV56PUEyxko4H/sR5pnHlduCGRDlFzQKXf/
|
||||
pMMmtj7cVb8=
|
||||
-----END CERTIFICATE-----
|
||||
'';
|
||||
extraCertificateFile = ./test-cert-file.crt;
|
||||
extraCertificatesToFingerprint = {
|
||||
# String above
|
||||
"NixOS cacert extra certificate string" = "A3:20:D0:84:96:97:25:FF:98:B8:A9:6D:A3:7C:89:95:6E:7A:77:21:92:F3:33:E9:31:AF:5E:03:CE:A9:E5:EE";
|
||||
|
||||
# File
|
||||
"NixOS cacert extra certificate file" = "88:B8:BE:A7:57:AC:F1:FE:D6:98:8B:50:E0:BD:0A:AE:88:C7:DF:70:26:E1:67:5E:F5:F6:91:27:FF:02:D4:A5";
|
||||
};
|
||||
mapExtra = f: lib.concatStringsSep "\n" (lib.mapAttrsToList f extraCertificatesToFingerprint);
|
||||
in runCommand "verify-the-cacert-extra-output" {
|
||||
cacert = cacert.unbundled;
|
||||
cacertWithExtras = (cacert.override {
|
||||
extraCertificateStrings = [ extraCertificateStr ];
|
||||
extraCertificateFiles = [ extraCertificateFile ];
|
||||
}).unbundled;
|
||||
|
||||
nativeBuildInputs = [ openssl ];
|
||||
} ''
|
||||
${isTrusted}
|
||||
|
||||
# Ensure that the extra certificate is not in the main "cacert".
|
||||
${mapExtra (extraName: extraFingerprint: ''
|
||||
isTrusted "$cacert" "${extraName}" "${extraFingerprint}" && ({
|
||||
echo "'extra' CA fingerprint ${extraFingerprint} (${extraName}) is present in the main CA bundle." >&2
|
||||
exit 1
|
||||
})
|
||||
'')}
|
||||
|
||||
# Ensure that the extra certificates ARE in the "cacertWithExtras".
|
||||
${mapExtra (extraName: extraFingerprint: ''
|
||||
isTrusted "$cacertWithExtras" "${extraName}" "${extraFingerprint}" || ({
|
||||
echo "CA fingerprint ${extraFingerprint} (${extraName}) is not present in the cacertWithExtras bundle." >&2
|
||||
exit 1
|
||||
})
|
||||
'')}
|
||||
|
||||
touch "$out"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
|
|
13
pkgs/data/misc/cacert/test-cert-file.crt
Normal file
13
pkgs/data/misc/cacert/test-cert-file.crt
Normal file
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIB7TCCAXSgAwIBAgIUFJB0STXn22fIEDjpncEt++IdFeMwCgYIKoZIzj0EAwIw
|
||||
LjEsMCoGA1UEAwwjTml4T1MgY2FjZXJ0IGV4dHJhIGNlcnRpZmljYXRlIGZpbGUw
|
||||
HhcNMjEwNjEyMTkxODA4WhcNMjIwNjEyMTkxODA4WjAuMSwwKgYDVQQDDCNOaXhP
|
||||
UyBjYWNlcnQgZXh0cmEgY2VydGlmaWNhdGUgZmlsZTB2MBAGByqGSM49AgEGBSuB
|
||||
BAAiA2IABMifTLM5K5xd+guGdKE1+NR7wnEJbxw5INzuMrkg/7jgEIQil4+L2YOF
|
||||
kU1gxcM80Ot8tQAG5OcSvX1DF6CxunpoCT+hnHqyfqoWFvl89i1BUKjyWCQ5WXEe
|
||||
nSkuJUmYC6NTMFEwHQYDVR0OBBYEFBE2kNis1ri4fweyNVRmvje83gFQMB8GA1Ud
|
||||
IwQYMBaAFBE2kNis1ri4fweyNVRmvje83gFQMA8GA1UdEwEB/wQFMAMBAf8wCgYI
|
||||
KoZIzj0EAwIDZwAwZAIwUZf1qaSb4cezulV+4B4FoJHY2B/nRVIi/rFD8634YEDT
|
||||
vcg6dmCi/AqLEzJn7uFMAjBVTu4EVC/mtQCGESFChMeb04fsuhXgttWSwWliVPEG
|
||||
jkG7u0UNNGaU8dvrjpqRRmA=
|
||||
-----END CERTIFICATE-----
|
Loading…
Reference in a new issue