Author: kevans
Date: Wed Oct  2 01:05:29 2019
New Revision: 352948
URL: https://svnweb.freebsd.org/changeset/base/352948

Log:
  [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

Added:
  head/secure/caroot/
  head/secure/caroot/MAca-bundle.pl   (contents, props changed)
  head/secure/caroot/Makefile   (contents, props changed)
  head/secure/caroot/README   (contents, props changed)
  head/secure/caroot/blacklisted/
  head/secure/caroot/blacklisted/Makefile   (contents, props changed)
  head/secure/caroot/trusted/
  head/secure/caroot/trusted/Makefile   (contents, props changed)
Modified:
  head/etc/mtree/BSD.usr.dist
  head/secure/Makefile
  head/share/mk/src.opts.mk

Modified: head/etc/mtree/BSD.usr.dist
==============================================================================
--- head/etc/mtree/BSD.usr.dist Tue Oct  1 23:28:22 2019        (r352947)
+++ head/etc/mtree/BSD.usr.dist Wed Oct  2 01:05:29 2019        (r352948)
@@ -194,6 +194,12 @@
             uk_UA.KOI8-U
             ..
         ..
+        certs
+            blacklisted
+            ..
+            trusted
+            ..
+        ..
         dict
         ..
         doc

Modified: head/secure/Makefile
==============================================================================
--- head/secure/Makefile        Tue Oct  1 23:28:22 2019        (r352947)
+++ head/secure/Makefile        Wed Oct  2 01:05:29 2019        (r352948)
@@ -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     \

Added: head/secure/caroot/MAca-bundle.pl
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/secure/caroot/MAca-bundle.pl   Wed Oct  2 01:05:29 2019        
(r352948)
@@ -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 <mand...@freebsd.org>
+##  All rights reserved.
+##  Copyright (c) 2018, Allan Jude <allanj...@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";

Added: head/secure/caroot/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/secure/caroot/Makefile Wed Oct  2 01:05:29 2019        (r352948)
@@ -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

Added: head/secure/caroot/README
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/secure/caroot/README   Wed Oct  2 01:05:29 2019        (r352948)
@@ -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.

Added: head/secure/caroot/blacklisted/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/secure/caroot/blacklisted/Makefile     Wed Oct  2 01:05:29 2019        
(r352948)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+BINDIR=                /usr/share/certs/blacklisted
+
+FILES=
+
+.include <bsd.prog.mk>

Added: head/secure/caroot/trusted/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/secure/caroot/trusted/Makefile Wed Oct  2 01:05:29 2019        
(r352948)
@@ -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>

Modified: head/share/mk/src.opts.mk
==============================================================================
--- head/share/mk/src.opts.mk   Tue Oct  1 23:28:22 2019        (r352947)
+++ head/share/mk/src.opts.mk   Wed Oct  2 01:05:29 2019        (r352948)
@@ -77,6 +77,7 @@ __DEFAULT_YES_OPTIONS = \
     BZIP2 \
     CALENDAR \
     CAPSICUM \
+    CAROOT \
     CASPER \
     CCD \
     CDDL \
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to