From f0b0be2c1faca90d8b73454a4d3b52b1e398f80c Mon Sep 17 00:00:00 2001 From: Kai Engert Date: Mon, 13 Feb 2017 21:04:08 +0100 Subject: [PATCH] - Changed the packaged bundle to use the flexible p11-kit-object-v1 file format, as a preparation to fix bugs in the interaction between p11-kit-trust and Mozilla applications, such as Firefox, Thunderbird etc. - Changed update-ca-trust to add comments to extracted PEM format files. - Added an utility to help with comparing output of the trust dump command. --- ca-certificates.spec | 95 +++++++++---------------- certdata2pem.py | 166 ++++++++++++++++++++++++++++++++++++++----- sort-blocks.py | 34 +++++++++ update-ca-trust | 8 +-- 4 files changed, 219 insertions(+), 84 deletions(-) create mode 100644 sort-blocks.py diff --git a/ca-certificates.spec b/ca-certificates.spec index 5ff5ad7..693e99a 100644 --- a/ca-certificates.spec +++ b/ca-certificates.spec @@ -1,11 +1,10 @@ %define pkidir %{_sysconfdir}/pki %define catrustdir %{_sysconfdir}/pki/ca-trust %define classic_tls_bundle ca-bundle.crt -%define trusted_all_bundle ca-bundle.trust.crt +%define openssl_format_trust_bundle ca-bundle.trust.crt +%define p11_format_bundle ca-bundle.trust.p11-kit %define legacy_default_bundle ca-bundle.legacy.default.crt %define legacy_disable_bundle ca-bundle.legacy.disable.crt -%define neutral_bundle ca-bundle.neutral-trust.crt -%define bundle_supplement ca-bundle.supplement.p11-kit %define java_bundle java/cacerts Summary: The Mozilla CA root certificate bundle @@ -39,7 +38,7 @@ Name: ca-certificates Version: 2017.2.11 # for Rawhide, please always use release >= 2 # for Fedora release branches, please use release < 2 (1.0, 1.1, ...) -Release: 3%{?dist} +Release: 4%{?dist} License: Public Domain Group: System Environment/Base @@ -96,11 +95,8 @@ pushd %{name} cat < %{trusted_all_bundle} - touch %{neutral_bundle} - for f in certs/*.crt; do - echo "processing $f" - tbits=`sed -n '/^# openssl-trust/{s/^.*=//;p;}' $f` - distbits=`sed -n '/^# openssl-distrust/{s/^.*=//;p;}' $f` - alias=`sed -n '/^# alias=/{s/^.*=//;p;q;}' $f | sed "s/'//g" | sed 's/"//g'` - targs="" - if [ -n "$tbits" ]; then - for t in $tbits; do - targs="${targs} -addtrust $t" - done - fi - if [ -n "$distbits" ]; then - for t in $distbits; do - targs="${targs} -addreject $t" - done - fi - if [ -n "$targs" ]; then - echo "trust flags $targs for $f" >> info.trust - openssl x509 -text -in "$f" -trustout $targs -setalias "$alias" >> %{trusted_all_bundle} - else - echo "no trust flags for $f" >> info.notrust - # p11-kit-trust defines empty trust lists as "rejected for all purposes". - # That's why we use the simple file format - # (BEGIN CERTIFICATE, no trust information) - # because p11-kit-trust will treat it as a certificate with neutral trust. - # This means we cannot use the -setalias feature for neutral trust certs. - openssl x509 -text -in "$f" >> %{neutral_bundle} - fi - done + ) > %{p11_format_bundle} touch %{legacy_default_bundle} NUM_LEGACY_DEFAULT=`find certs/legacy-default -type f | wc -l` @@ -181,14 +147,14 @@ EOF done fi - P11FILES=`find certs -name *.p11-kit | wc -l` + P11FILES=`find certs -name \*.tmp-p11-kit | wc -l` if [ $P11FILES -ne 0 ]; then - for p in certs/*.p11-kit; do - cat "$p" >> %{bundle_supplement} + for p in certs/*.tmp-p11-kit; do + cat "$p" >> %{p11_format_bundle} done fi # Append our trust fixes - cat %{SOURCE3} >> %{bundle_supplement} + cat %{SOURCE3} >> %{p11_format_bundle} popd #manpage @@ -230,18 +196,14 @@ install -p -m 644 %{SOURCE15} $RPM_BUILD_ROOT%{catrustdir}/extracted/openssl/REA install -p -m 644 %{SOURCE16} $RPM_BUILD_ROOT%{catrustdir}/extracted/pem/README install -p -m 644 %{SOURCE17} $RPM_BUILD_ROOT%{catrustdir}/source/README -install -p -m 644 %{name}/%{trusted_all_bundle} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{trusted_all_bundle} -install -p -m 644 %{name}/%{neutral_bundle} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{neutral_bundle} -install -p -m 644 %{name}/%{bundle_supplement} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{bundle_supplement} +install -p -m 644 %{name}/%{p11_format_bundle} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{p11_format_bundle} install -p -m 644 %{name}/%{legacy_default_bundle} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-legacy/%{legacy_default_bundle} install -p -m 644 %{name}/%{legacy_disable_bundle} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-legacy/%{legacy_disable_bundle} install -p -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{catrustdir}/ca-legacy.conf -touch -r %{SOURCE0} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{trusted_all_bundle} -touch -r %{SOURCE0} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{neutral_bundle} -touch -r %{SOURCE0} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{bundle_supplement} +touch -r %{SOURCE0} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-source/%{p11_format_bundle} touch -r %{SOURCE0} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-legacy/%{legacy_default_bundle} touch -r %{SOURCE0} $RPM_BUILD_ROOT%{_datadir}/pki/ca-trust-legacy/%{legacy_disable_bundle} @@ -256,7 +218,7 @@ install -p -m 755 %{SOURCE6} $RPM_BUILD_ROOT%{_bindir}/ca-legacy touch $RPM_BUILD_ROOT%{catrustdir}/extracted/pem/tls-ca-bundle.pem touch $RPM_BUILD_ROOT%{catrustdir}/extracted/pem/email-ca-bundle.pem touch $RPM_BUILD_ROOT%{catrustdir}/extracted/pem/objsign-ca-bundle.pem -touch $RPM_BUILD_ROOT%{catrustdir}/extracted/openssl/%{trusted_all_bundle} +touch $RPM_BUILD_ROOT%{catrustdir}/extracted/openssl/%{openssl_format_trust_bundle} touch $RPM_BUILD_ROOT%{catrustdir}/extracted/%{java_bundle} # /etc/ssl/certs symlink for 3rd-party tools @@ -267,8 +229,8 @@ sln %{catrustdir}/extracted/pem/tls-ca-bundle.pem \ $RPM_BUILD_ROOT%{pkidir}/tls/cert.pem sln %{catrustdir}/extracted/pem/tls-ca-bundle.pem \ $RPM_BUILD_ROOT%{pkidir}/tls/certs/%{classic_tls_bundle} -sln %{catrustdir}/extracted/openssl/%{trusted_all_bundle} \ - $RPM_BUILD_ROOT%{pkidir}/tls/certs/%{trusted_all_bundle} +sln %{catrustdir}/extracted/openssl/%{openssl_format_trust_bundle} \ + $RPM_BUILD_ROOT%{pkidir}/tls/certs/%{openssl_format_trust_bundle} sln %{catrustdir}/extracted/%{java_bundle} \ $RPM_BUILD_ROOT%{pkidir}/%{java_bundle} @@ -310,13 +272,13 @@ if [ $1 -gt 1 ] ; then fi fi - if ! test -e %{pkidir}/tls/certs/%{trusted_all_bundle}.rpmsave; then + if ! test -e %{pkidir}/tls/certs/%{openssl_format_trust_bundle}.rpmsave; then # no backup yet - if test -e %{pkidir}/tls/certs/%{trusted_all_bundle}; then + if test -e %{pkidir}/tls/certs/%{openssl_format_trust_bundle}; then # a file exists - if ! test -L %{pkidir}/tls/certs/%{trusted_all_bundle}; then + if ! test -L %{pkidir}/tls/certs/%{openssl_format_trust_bundle}; then # it's an old regular file, not a link - mv -f %{pkidir}/tls/certs/%{trusted_all_bundle} %{pkidir}/tls/certs/%{trusted_all_bundle}.rpmsave + mv -f %{pkidir}/tls/certs/%{openssl_format_trust_bundle} %{pkidir}/tls/certs/%{openssl_format_trust_bundle}.rpmsave fi fi fi @@ -367,14 +329,14 @@ fi # symlinks for old locations %{pkidir}/tls/cert.pem %{pkidir}/tls/certs/%{classic_tls_bundle} -%{pkidir}/tls/certs/%{trusted_all_bundle} +%{pkidir}/tls/certs/%{openssl_format_trust_bundle} %{pkidir}/%{java_bundle} # symlink directory %{_sysconfdir}/ssl/certs + # master bundle file with trust -%{_datadir}/pki/ca-trust-source/%{trusted_all_bundle} -%{_datadir}/pki/ca-trust-source/%{neutral_bundle} -%{_datadir}/pki/ca-trust-source/%{bundle_supplement} +%{_datadir}/pki/ca-trust-source/%{p11_format_bundle} + %{_datadir}/pki/ca-trust-legacy/%{legacy_default_bundle} %{_datadir}/pki/ca-trust-legacy/%{legacy_disable_bundle} # update/extract tool @@ -385,18 +347,25 @@ fi %ghost %{catrustdir}/extracted/pem/tls-ca-bundle.pem %ghost %{catrustdir}/extracted/pem/email-ca-bundle.pem %ghost %{catrustdir}/extracted/pem/objsign-ca-bundle.pem -%ghost %{catrustdir}/extracted/openssl/%{trusted_all_bundle} +%ghost %{catrustdir}/extracted/openssl/%{openssl_format_trust_bundle} %ghost %{catrustdir}/extracted/%{java_bundle} %changelog +* Mon Feb 13 2017 Kai Engert - 2017.2.11-4 +- Changed the packaged bundle to use the flexible p11-kit-object-v1 file format, + as a preparation to fix bugs in the interaction between p11-kit-trust and + Mozilla applications, such as Firefox, Thunderbird etc. +- Changed update-ca-trust to add comments to extracted PEM format files. +- Added an utility to help with comparing output of the trust dump command. + * Fri Feb 10 2017 Fedora Release Engineering - 2017.2.11-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild * Wed Jan 11 2017 Kai Engert - 2017.2.11-2 - Update to CKBI 2.11 from NSS 3.28.1 -* Fri Sep 29 2016 Kai Engert - 2016.2.10-2 +* Thu Sep 29 2016 Kai Engert - 2016.2.10-2 - Update to CKBI 2.10 from NSS 3.27 * Tue Aug 16 2016 Kai Engert - 2016.2.9-3 diff --git a/certdata2pem.py b/certdata2pem.py index 44cc9e0..db6090d 100644 --- a/certdata2pem.py +++ b/certdata2pem.py @@ -27,6 +27,7 @@ import re import sys import textwrap import urllib +import subprocess objects = [] @@ -113,6 +114,16 @@ def obj_to_filename(obj): serial = printable_serial(obj) return label + ":" + serial +def write_cert_ext_to_file(f, oid, value, public_key): + f.write("[p11-kit-object-v1]\n") + f.write("label: "); + f.write(tobj['CKA_LABEL']) + f.write("\n") + f.write("class: x-certificate-extension\n"); + f.write("object-id: " + oid + "\n") + f.write("value: \"" + value + "\"\n") + f.write(public_key) + trust_types = { "CKA_TRUST_DIGITAL_SIGNATURE": "digital-signature", "CKA_TRUST_NON_REPUDIATION": "non-repudiation", @@ -186,17 +197,20 @@ for tobj in objects: except: obj = None - if obj != None: - fname += ".crt" - else: - fname += ".p11-kit" + # optional debug code, that dumps the parsed input to files + #fulldump = "dump-" + fname + #dumpf = open(fulldump, 'w') + #dumpf.write(str(obj)); + #dumpf.write(str(tobj)); + #dumpf.close(); is_legacy = 0 if tobj.has_key('LEGACY_CKA_TRUST_SERVER_AUTH') or tobj.has_key('LEGACY_CKA_TRUST_EMAIL_PROTECTION') or tobj.has_key('LEGACY_CKA_TRUST_CODE_SIGNING'): is_legacy = 1 if obj == None: raise NotImplementedError, 'found legacy trust without certificate.\n' + line - legacy_fname = "legacy-default/" + fname + + legacy_fname = "legacy-default/" + fname + ".crt" f = open(legacy_fname, 'w') f.write("# alias=%s\n"%tobj['CKA_LABEL']) f.write("# trust=" + " ".join(legacy_trustbits) + "\n") @@ -206,23 +220,141 @@ for tobj in objects: f.write("\n".join(textwrap.wrap(base64.b64encode(obj['CKA_VALUE']), 64))) f.write("\n-----END CERTIFICATE-----\n") f.close() - if tobj.has_key('CKA_TRUST_SERVER_AUTH') or tobj.has_key('CKA_TRUST_EMAIL_PROTECTION') or tobj.has_key('CKA_TRUST_CODE_SIGNING'): - fname = "legacy-disable/" + fname - else: - continue - f = open(fname, 'w') + if tobj.has_key('CKA_TRUST_SERVER_AUTH') or tobj.has_key('CKA_TRUST_EMAIL_PROTECTION') or tobj.has_key('CKA_TRUST_CODE_SIGNING'): + legacy_fname = "legacy-disable/" + fname + ".crt" + f = open(legacy_fname, 'w') + f.write("# alias=%s\n"%tobj['CKA_LABEL']) + f.write("# trust=" + " ".join(trustbits) + "\n") + if openssl_trustflags: + f.write("# openssl-trust=" + " ".join(openssl_trustflags) + "\n") + f.write("-----BEGIN CERTIFICATE-----\n") + f.write("\n".join(textwrap.wrap(base64.b64encode(obj['CKA_VALUE']), 64))) + f.write("\n-----END CERTIFICATE-----\n") + f.close() + + # don't produce p11-kit output for legacy certificates + continue + + pk = '' + cert_comment = '' if obj != None: - f.write("# alias=%s\n"%tobj['CKA_LABEL']) - f.write("# trust=" + " ".join(trustbits) + "\n") - f.write("# distrust=" + " ".join(distrustbits) + "\n") - if openssl_trustflags: - f.write("# openssl-trust=" + " ".join(openssl_trustflags) + "\n") - if openssl_distrustflags: - f.write("# openssl-distrust=" + " ".join(openssl_distrustflags) + "\n") + # must extract the public key from the cert, let's use openssl + cert_fname = "cert-" + fname + fc = open(cert_fname, 'w') + fc.write("-----BEGIN CERTIFICATE-----\n") + fc.write("\n".join(textwrap.wrap(base64.b64encode(obj['CKA_VALUE']), 64))) + fc.write("\n-----END CERTIFICATE-----\n") + fc.close(); + pk_fname = "pubkey-" + fname + fpkout = open(pk_fname, "w") + dump_pk_command = ["openssl", "x509", "-in", cert_fname, "-noout", "-pubkey"] + subprocess.call(dump_pk_command, stdout=fpkout) + fpkout.close() + with open (pk_fname, "r") as myfile: + pk=myfile.read() + # obtain certificate information suitable as a comment + comment_fname = "comment-" + fname + fcout = open(comment_fname, "w") + comment_command = ["openssl", "x509", "-in", cert_fname, "-noout", "-text"] + subprocess.call(comment_command, stdout=fcout) + fcout.close() + sed_command = ["sed", "--in-place", "s/^/#/", comment_fname] + subprocess.call(sed_command) + with open (comment_fname, "r") as myfile: + cert_comment=myfile.read() + + fname += ".tmp-p11-kit" + f = open(fname, 'w') + + if obj != None: + is_distrusted = False + has_server_trust = False + has_email_trust = False + has_code_trust = False + + if tobj.has_key('CKA_TRUST_SERVER_AUTH'): + if tobj['CKA_TRUST_SERVER_AUTH'] == 'CKT_NSS_NOT_TRUSTED': + is_distrusted = True + elif tobj['CKA_TRUST_SERVER_AUTH'] == 'CKT_NSS_TRUSTED_DELEGATOR': + has_server_trust = True + + if tobj.has_key('CKA_TRUST_EMAIL_PROTECTION'): + if tobj['CKA_TRUST_EMAIL_PROTECTION'] == 'CKT_NSS_NOT_TRUSTED': + is_distrusted = True + elif tobj['CKA_TRUST_EMAIL_PROTECTION'] == 'CKT_NSS_TRUSTED_DELEGATOR': + has_email_trust = True + + if tobj.has_key('CKA_TRUST_CODE_SIGNING'): + if tobj['CKA_TRUST_CODE_SIGNING'] == 'CKT_NSS_NOT_TRUSTED': + is_distrusted = True + elif tobj['CKA_TRUST_CODE_SIGNING'] == 'CKT_NSS_TRUSTED_DELEGATOR': + has_code_trust = True + + if is_distrusted: + trust_ext_oid = "1.3.6.1.4.1.3319.6.10.1" + trust_ext_value = "0.%06%0a%2b%06%01%04%01%99w%06%0a%01%04 0%1e%06%08%2b%06%01%05%05%07%03%04%06%08%2b%06%01%05%05%07%03%01%06%08%2b%06%01%05%05%07%03%03" + write_cert_ext_to_file(f, trust_ext_oid, trust_ext_value, pk) + + trust_ext_oid = "2.5.29.37" + if has_server_trust: + if has_email_trust: + if has_code_trust: + # server + email + code + trust_ext_value = "0%2a%06%03U%1d%25%01%01%ff%04 0%1e%06%08%2b%06%01%05%05%07%03%04%06%08%2b%06%01%05%05%07%03%01%06%08%2b%06%01%05%05%07%03%03" + else: + # server + email + trust_ext_value = "0 %06%03U%1d%25%01%01%ff%04%160%14%06%08%2b%06%01%05%05%07%03%04%06%08%2b%06%01%05%05%07%03%01" + else: + if has_code_trust: + # server + code + trust_ext_value = "0 %06%03U%1d%25%01%01%ff%04%160%14%06%08%2b%06%01%05%05%07%03%01%06%08%2b%06%01%05%05%07%03%03" + else: + # server + trust_ext_value = "0%16%06%03U%1d%25%01%01%ff%04%0c0%0a%06%08%2b%06%01%05%05%07%03%01" + else: + if has_email_trust: + if has_code_trust: + # email + code + trust_ext_value = "0 %06%03U%1d%25%01%01%ff%04%160%14%06%08%2b%06%01%05%05%07%03%04%06%08%2b%06%01%05%05%07%03%03" + else: + # email + trust_ext_value = "0%16%06%03U%1d%25%01%01%ff%04%0c0%0a%06%08%2b%06%01%05%05%07%03%04" + else: + if has_code_trust: + # code + trust_ext_value = "0%16%06%03U%1d%25%01%01%ff%04%0c0%0a%06%08%2b%06%01%05%05%07%03%03" + else: + # none + trust_ext_value = "0%18%06%03U%1d%25%01%01%ff%04%0e0%0c%06%0a%2b%06%01%04%01%99w%06%0a%10" + + # no 2.5.29.37 for neutral certificates + if (is_distrusted or has_server_trust or has_email_trust or has_code_trust): + write_cert_ext_to_file(f, trust_ext_oid, trust_ext_value, pk) + + pk = '' + f.write("\n") + + f.write("[p11-kit-object-v1]\n") + f.write("label: "); + f.write(tobj['CKA_LABEL']) + f.write("\n") + if is_distrusted: + f.write("x-distrusted: true\n") + elif has_server_trust or has_email_trust or has_code_trust: + f.write("trusted: true\n") + else: + f.write("trusted: false\n") + + # enable the following line, after we have upgraded p11-kit-trust + # f.write("nss-mozilla-ca-policy: true\n") + f.write("-----BEGIN CERTIFICATE-----\n") f.write("\n".join(textwrap.wrap(base64.b64encode(obj['CKA_VALUE']), 64))) f.write("\n-----END CERTIFICATE-----\n") + f.write(cert_comment) + f.write("\n") + else: f.write("[p11-kit-object-v1]\n") f.write("label: "); diff --git a/sort-blocks.py b/sort-blocks.py new file mode 100644 index 0000000..2d7365b --- /dev/null +++ b/sort-blocks.py @@ -0,0 +1,34 @@ +#!/usr/bin/python + +# Expected input is a file, where blocks of lines are separated by newline. +# Blocks will be sorted. +# Intention is to prepare files for comparison, were lines inside each block are +# in stable order, but the order of blocks is random. + +import sys +import string + +if (len(sys.argv) != 2): + print "syntax: " + sys.argv[0] + " input-filename" + sys.exit(1) + +filename = sys.argv[1] + +block = [] +block_list = [] +with open(filename, 'r') as f: + for line in f: + if (len(line) == 1): + if len(block) == 0: + continue + else: + combined_string = string.join(block, '') + block_list.append(combined_string) + block = [] + else: + block.append(line) + +block_list.sort() + +for block in block_list: + print block diff --git a/update-ca-trust b/update-ca-trust index a5518d1..d65f248 100644 --- a/update-ca-trust +++ b/update-ca-trust @@ -11,8 +11,8 @@ DEST=/etc/pki/ca-trust/extracted # OpenSSL PEM bundle that includes trust flags # (BEGIN TRUSTED CERTIFICATE) -/usr/bin/p11-kit extract --format=openssl-bundle --filter=certificates --overwrite $DEST/openssl/ca-bundle.trust.crt -/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --purpose server-auth $DEST/pem/tls-ca-bundle.pem -/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --purpose email $DEST/pem/email-ca-bundle.pem -/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --purpose code-signing $DEST/pem/objsign-ca-bundle.pem +/usr/bin/p11-kit extract --format=openssl-bundle --filter=certificates --overwrite --comment $DEST/openssl/ca-bundle.trust.crt +/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --comment --purpose server-auth $DEST/pem/tls-ca-bundle.pem +/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --comment --purpose email $DEST/pem/email-ca-bundle.pem +/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --comment --purpose code-signing $DEST/pem/objsign-ca-bundle.pem /usr/bin/p11-kit extract --format=java-cacerts --filter=ca-anchors --overwrite --purpose server-auth $DEST/java/cacerts