summaryrefslogtreecommitdiff
path: root/secure
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2019-10-02 01:05:29 +0000
committerKyle Evans <kevans@FreeBSD.org>2019-10-02 01:05:29 +0000
commitf27f39db77d253836070f5d83a5759c3da44a0c1 (patch)
tree61a1877573f2ce7d6d3ea3e5289d08d33cd77a02 /secure
parent150c95edfe0a859fcb52b65c64b2af5ebcdcb5cd (diff)
downloadsrc-test2-f27f39db77d253836070f5d83a5759c3da44a0c1.tar.gz
src-test2-f27f39db77d253836070f5d83a5759c3da44a0c1.zip
[1/3] Initial infrastructure for SSL root bundle in base
This setup will add the trusted certificates from the Mozilla NSS bundle to base. This commit includes: - CAROOT option to opt out of installation of certs - mtree amendments for final destinations - infrastructure to fetch/update certs, along with instructions A follow-up commit will add a certctl(8) utility to give the user control over trust specifics. Another follow-up commit will actually commit the initial result of updatecerts. This work was done primarily by allanjude@, with minor contributions by myself. No objection from: secteam Relnotes: yes Differential Revision: https://reviews.freebsd.org/D16856
Notes
Notes: svn path=/head/; revision=352948
Diffstat (limited to 'secure')
-rw-r--r--secure/Makefile2
-rwxr-xr-xsecure/caroot/MAca-bundle.pl272
-rw-r--r--secure/caroot/Makefile21
-rw-r--r--secure/caroot/README34
-rw-r--r--secure/caroot/blacklisted/Makefile7
-rw-r--r--secure/caroot/trusted/Makefile12
6 files changed, 348 insertions, 0 deletions
diff --git a/secure/Makefile b/secure/Makefile
index c8d12502740d..198df326fe32 100644
--- a/secure/Makefile
+++ b/secure/Makefile
@@ -8,6 +8,8 @@ SUBDIR_PARALLEL=
SUBDIR.${MK_TESTS}+= tests
+SUBDIR.${MK_CAROOT}+= caroot
+
# These are the programs which depend on crypto, but not Kerberos.
SPROGS= lib/libfetch lib/libpam lib/libradius lib/libtelnet \
bin/ed libexec/telnetd usr.bin/fetch usr.bin/telnet \
diff --git a/secure/caroot/MAca-bundle.pl b/secure/caroot/MAca-bundle.pl
new file mode 100755
index 000000000000..c84e83a3c730
--- /dev/null
+++ b/secure/caroot/MAca-bundle.pl
@@ -0,0 +1,272 @@
+#!/usr/bin/env perl
+##
+## MAca-bundle.pl -- Regenerate ca-root-nss.crt from the Mozilla certdata.txt
+##
+## Rewritten in September 2011 by Matthias Andree to heed untrust
+##
+
+## Copyright (c) 2011, 2013 Matthias Andree <mandree@FreeBSD.org>
+## All rights reserved.
+## Copyright (c) 2018, Allan Jude <allanjude@FreeBSD.org>
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are
+## met:
+##
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+## FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+## COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+## ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+## POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use Carp;
+use MIME::Base64;
+use Getopt::Long;
+
+my $VERSION = '$FreeBSD$';
+my $inputfh = *STDIN;
+my $debug = 0;
+my $infile;
+my $outputdir;
+my %labels;
+my %certs;
+my %trusts;
+
+$debug++
+ if defined $ENV{'WITH_DEBUG'}
+ and $ENV{'WITH_DEBUG'} !~ m/(?i)^(no|0|false|)$/;
+
+GetOptions (
+ "debug+" => \$debug,
+ "infile:s" => \$infile,
+ "outputdir:s" => \$outputdir)
+ or die("Error in command line arguments\n$0 [-d] [-i input-file] [-o output-dir]\n");
+
+if ($infile) {
+ open($inputfh, "<", $infile) or die "Failed to open $infile";
+}
+
+sub print_header($$)
+{
+ my $dstfile = shift;
+ my $label = shift;
+
+ if ($outputdir) {
+ print $dstfile <<EOFH;
+##
+## $label
+##
+## This is a single X.509 certificate for a public Certificate
+## Authority (CA). It was automatically extracted from Mozilla's
+## root CA list (the file `certdata.txt' in security/nss).
+##
+## Extracted from nss
+## with $VERSION
+##
+EOFH
+ } else {
+ print $dstfile <<EOH;
+##
+## ca-root-nss.crt -- Bundle of CA Root Certificates
+##
+## This is a bundle of X.509 certificates of public Certificate
+## Authorities (CA). These were automatically extracted from Mozilla's
+## root CA list (the file `certdata.txt').
+##
+## Extracted from nss
+## with $VERSION
+##
+EOH
+ }
+}
+
+sub printcert($$$)
+{
+ my ($fh, $label, $certdata) = @_;
+ return unless $certdata;
+ open(OUT, "|openssl x509 -text -inform DER -fingerprint")
+ or die "could not pipe to openssl x509";
+ print OUT $certdata;
+ close(OUT) or die "openssl x509 failed with exit code $?";
+}
+
+sub graboct($)
+{
+ my $ifh = shift;
+ my $data;
+
+ while (<$ifh>) {
+ last if /^END/;
+ my (undef,@oct) = split /\\/;
+ my @bin = map(chr(oct), @oct);
+ $data .= join('', @bin);
+ }
+
+ return $data;
+}
+
+
+sub grabcert($)
+{
+ my $ifh = shift;
+ my $certdata;
+ my $cka_label;
+ my $serial;
+
+ while (<$ifh>) {
+ chomp;
+ last if ($_ eq '');
+
+ if (/^CKA_LABEL UTF8 "([^"]+)"/) {
+ $cka_label = $1;
+ }
+
+ if (/^CKA_VALUE MULTILINE_OCTAL/) {
+ $certdata = graboct($ifh);
+ }
+
+ if (/^CKA_SERIAL_NUMBER MULTILINE_OCTAL/) {
+ $serial = graboct($ifh);
+ }
+ }
+ return ($serial, $cka_label, $certdata);
+}
+
+sub grabtrust($) {
+ my $ifh = shift;
+ my $cka_label;
+ my $serial;
+ my $maytrust = 0;
+ my $distrust = 0;
+
+ while (<$ifh>) {
+ chomp;
+ last if ($_ eq '');
+
+ if (/^CKA_LABEL UTF8 "([^"]+)"/) {
+ $cka_label = $1;
+ }
+
+ if (/^CKA_SERIAL_NUMBER MULTILINE_OCTAL/) {
+ $serial = graboct($ifh);
+ }
+
+ if (/^CKA_TRUST_(SERVER_AUTH|EMAIL_PROTECTION|CODE_SIGNING) CK_TRUST (\S+)$/)
+ {
+ if ($2 eq 'CKT_NSS_NOT_TRUSTED') {
+ $distrust = 1;
+ } elsif ($2 eq 'CKT_NSS_TRUSTED_DELEGATOR') {
+ $maytrust = 1;
+ } elsif ($2 ne 'CKT_NSS_MUST_VERIFY_TRUST') {
+ confess "Unknown trust setting on line $.:\n"
+ . "$_\n"
+ . "Script must be updated:";
+ }
+ }
+ }
+
+ if (!$maytrust && !$distrust && $debug) {
+ print STDERR "line $.: no explicit trust/distrust found for $cka_label\n";
+ }
+
+ my $trust = ($maytrust and not $distrust);
+ return ($serial, $cka_label, $trust);
+}
+
+if (!$outputdir) {
+ print_header(*STDOUT, "");
+}
+
+while (<$inputfh>) {
+ if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) {
+ my ($serial, $label, $certdata) = grabcert($inputfh);
+ if (defined $certs{$label."\0".$serial}) {
+ warn "Certificate $label duplicated!\n";
+ }
+ $certs{$label."\0".$serial} = $certdata;
+ # We store the label in a separate hash because truncating the key
+ # with \0 was causing garbage data after the end of the text.
+ $labels{$label."\0".$serial} = $label;
+ } elsif (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/) {
+ my ($serial, $label, $trust) = grabtrust($inputfh);
+ if (defined $trusts{$label."\0".$serial}) {
+ warn "Trust for $label duplicated!\n";
+ }
+ $trusts{$label."\0".$serial} = $trust;
+ $labels{$label."\0".$serial} = $label;
+ } elsif (/^CVS_ID.*Revision: ([^ ]*).*/) {
+ print "## Source: \"certdata.txt\" CVS revision $1\n##\n\n";
+ }
+}
+
+sub label_to_filename(@) {
+ my @res = @_;
+ map { s/\0.*//; s/[^[:alnum:]\-]/_/g; $_ = "$_.pem"; } @res;
+ return wantarray ? @res : $res[0];
+}
+
+# weed out untrusted certificates
+my $untrusted = 0;
+foreach my $it (keys %trusts) {
+ if (!$trusts{$it}) {
+ if (!exists($certs{$it})) {
+ warn "Found trust for nonexistent certificate $labels{$it}\n" if $debug;
+ } else {
+ delete $certs{$it};
+ warn "Skipping untrusted $labels{$it}\n" if $debug;
+ $untrusted++;
+ }
+ }
+}
+
+if (!$outputdir) {
+ print "## Untrusted certificates omitted from this bundle: $untrusted\n\n";
+}
+print STDERR "## Untrusted certificates omitted from this bundle: $untrusted\n";
+
+my $certcount = 0;
+foreach my $it (sort {uc($a) cmp uc($b)} keys %certs) {
+ my $fh = *STDOUT;
+ my $filename;
+ if (!exists($trusts{$it})) {
+ die "Found certificate without trust block,\naborting";
+ }
+ if ($outputdir) {
+ $filename = label_to_filename($labels{$it});
+ open($fh, ">", "$outputdir/$filename") or die "Failed to open certificate $filename";
+ print_header($fh, $labels{$it});
+ }
+ printcert($fh, $labels{$it}, $certs{$it});
+ if ($outputdir) {
+ close($fh) or die "Unable to close: $filename";
+ } else {
+ print $fh "\n\n\n";
+ }
+ $certcount++;
+ print STDERR "Trusting $certcount: $labels{$it}\n" if $debug;
+}
+
+if ($certcount < 25) {
+ die "Certificate count of $certcount is implausibly low.\nAbort";
+}
+
+if (!$outputdir) {
+ print "## Number of certificates: $certcount\n";
+ print "## End of file.\n";
+}
+print STDERR "## Number of certificates: $certcount\n";
diff --git a/secure/caroot/Makefile b/secure/caroot/Makefile
new file mode 100644
index 000000000000..c9d39d71bad9
--- /dev/null
+++ b/secure/caroot/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+PACKAGE= caroot
+
+CLEANFILES+= certdata.txt
+
+SUBDIR+= trusted
+SUBDIR+= blacklisted
+
+.include <bsd.prog.mk>
+
+# To be used by secteam@ to update the trusted certificates
+
+fetchcerts: .PHONY
+ fetch --no-sslv3 --no-tlsv1 -o certdata.txt 'https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt'
+
+cleancerts: .PHONY
+ @${MAKE} -C ${.CURDIR}/trusted ${.TARGET}
+
+updatecerts: .PHONY cleancerts fetchcerts
+ perl ${.CURDIR}/MAca-bundle.pl -i certdata.txt -o ${.CURDIR}/trusted
diff --git a/secure/caroot/README b/secure/caroot/README
new file mode 100644
index 000000000000..9a4fc0320e2a
--- /dev/null
+++ b/secure/caroot/README
@@ -0,0 +1,34 @@
+# $FreeBSD$
+
+This directory contains the scripts to update the TLS CA Root Certificates
+that comprise the 'root trust store'.
+
+The 'updatecerts' make target should be run periodically by secteam@
+specifically when there is an important change to the list of trusted root
+certificates included by Mozilla.
+
+It will:
+ 1) Remove the old trusted certificates (cleancerts)
+ 2) Download the latest certdata.txt from Mozilla (fetchcerts)
+ 3) Split certdata.txt into the individual .pem files (updatecerts)
+
+Then the results should manually be inspected (svn status)
+ 1) Any no-longer-trusted certificates should be moved to the
+ blacklisted directory (svn mv)
+ 2) any newly added certificates will need to be added (svn add)
+
+
+The following make targets exist:
+
+cleancerts:
+ Delete the old certificates, run as a dependency of updatecerts.
+
+fetchcerts:
+ Download the latest certdata.txt from the Mozilla NSS hg repo
+ See the changelog here:
+ https://hg.mozilla.org/projects/nss/log/tip/lib/ckfw/builtins/certdata.txt
+
+updatecerts:
+ Runs a perl script (MAca-bundle.pl) on the downloaded certdata.txt
+ to generate the individual certificate files (.pem) and store them
+ in the trusted/ directory.
diff --git a/secure/caroot/blacklisted/Makefile b/secure/caroot/blacklisted/Makefile
new file mode 100644
index 000000000000..7691993416b3
--- /dev/null
+++ b/secure/caroot/blacklisted/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+BINDIR= /usr/share/certs/blacklisted
+
+FILES=
+
+.include <bsd.prog.mk>
diff --git a/secure/caroot/trusted/Makefile b/secure/caroot/trusted/Makefile
new file mode 100644
index 000000000000..f159edddff05
--- /dev/null
+++ b/secure/caroot/trusted/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+BINDIR= /usr/share/certs/trusted
+
+TRUSTED_CERTS!= ls ${.CURDIR}/*.pem 2> /dev/null || true
+
+FILES+= ${TRUSTED_CERTS}
+
+cleancerts:
+ @[ -z "${TRUSTED_CERTS}" ] || rm ${TRUSTED_CERTS}
+
+.include <bsd.prog.mk>