diff --git a/secure/caroot/MAca-bundle.pl b/secure/caroot/MAca-bundle.pl --- a/secure/caroot/MAca-bundle.pl +++ b/secure/caroot/MAca-bundle.pl @@ -8,6 +8,7 @@ ## Copyright (c) 2011, 2013 Matthias Andree ## All rights reserved. ## Copyright (c) 2018, Allan Jude +## Copyright (c) 2025 Dag-Erling Smørgrav ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are @@ -34,6 +35,7 @@ ## POSSIBILITY OF SUCH DAMAGE. use strict; +use warnings; use Carp; use MIME::Base64; use Getopt::Long; @@ -44,10 +46,12 @@ my $inputfh = *STDIN; my $debug = 0; my $infile; -my $outputdir; +my $trustdir = "trusted"; +my $untrustdir = "untrusted"; my %labels; my %certs; my %trusts; +my %expires; $debug++ if defined $ENV{'WITH_DEBUG'} @@ -56,8 +60,9 @@ 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"); + "trustdir:s" => \$trustdir, + "untrustdir:s" => \$untrustdir) + or die("Error in command line arguments\n$0 [-d] [-i input-file] [-t trust-dir] [-u untrust-dir]\n"); if ($infile) { open($inputfh, "<", $infile) or die "Failed to open $infile"; @@ -68,8 +73,7 @@ my $dstfile = shift; my $label = shift; - if ($outputdir) { - print $dstfile <) { last if /^END/; - my (undef,@oct) = split /\\/; - my @bin = map(chr(oct), @oct); - $data .= join('', @bin); + $data .= join('', map { chr(oct($_)) } m/\\([0-7]{3})/g); } return $data; @@ -158,18 +139,8 @@ { my $distrust_after = graboct($ifh); my ($year, $mon, $mday, $hour, $min, $sec) = unpack "A2A2A2A2A2A2", $distrust_after; - $distrust_after = timegm_posix( $sec, $min, $hour, $mday, $mon - 1, $year + 100); - my $time_now = time; - # When a CA is distrusted before its NotAfter date, issued certificates - # are valid for a maximum of 398 days after that date. - if ($time_now >= $distrust_after + 398 * 24 * 60 * 60) { $distrust = 1; } - if ($debug) { - printf STDERR "line $.: $cka_label ser #%d: distrust 398 days after %s, now: %s -> distrust $distrust\n", $serial, - strftime("%FT%TZ", gmtime($distrust_after)), strftime("%FT%TZ", gmtime($time_now)); - } - if ($distrust) { - return undef; - } + $distrust_after = timegm_posix($sec, $min, $hour, $mday, $mon - 1, $year + 100); + $expires{$cka_label."\0".$serial} = $distrust_after; } } return ($serial, $cka_label, $certdata); @@ -194,8 +165,7 @@ $serial = graboct($ifh); } - if (/^CKA_TRUST_SERVER_AUTH CK_TRUST (\S+)$/) - { + if (/^CKA_TRUST_SERVER_AUTH CK_TRUST (\S+)$/) { if ($1 eq 'CKT_NSS_NOT_TRUSTED') { $distrust = 1; } elsif ($1 eq 'CKT_NSS_TRUSTED_DELEGATOR') { @@ -216,12 +186,6 @@ return ($serial, $cka_label, $trust); } -if (!$outputdir) { - print_header(*STDOUT, ""); -} - -my $untrusted = 0; - while (<$inputfh>) { if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { my ($serial, $label, $certdata) = grabcert($inputfh); @@ -229,12 +193,10 @@ warn "Certificate $label duplicated!\n"; } if (defined $certdata) { - $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; - } else { # $certdata undefined? distrust_after in effect - $untrusted ++; + $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); @@ -254,52 +216,38 @@ return wantarray ? @res : $res[0]; } -# weed out untrusted certificates -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 $untrusted = 0; +my $trusted = 0; +my $now = time; -my $certcount = 0; foreach my $it (sort {uc($a) cmp uc($b)} keys %certs) { my $fh = *STDOUT; + my $outputdir; 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}); + if (exists($expires{$it}) && + $now >= $expires{$it} + 398 * 24 * 60 * 60) { + print(STDERR "## Expired: $labels{$it}\n"); + $outputdir = $untrustdir; + $untrusted++; + } elsif (!$trusts{$it}) { + print(STDERR "## Untrusted: $labels{$it}\n"); + $outputdir = $untrustdir; + $untrusted++; + } else { + print(STDERR "## Trusted: $labels{$it}\n"); + $outputdir = $trustdir; + $trusted++; } + $filename = label_to_filename($labels{$it}); + open($fh, ">", "$outputdir/$filename") or die "Failed to open certificate $outputdir/$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"; +printf STDERR "## Trusted certificates: %4d\n", $trusted; +printf STDERR "## Untrusted certificates: %4d\n", $untrusted; diff --git a/secure/caroot/Makefile b/secure/caroot/Makefile --- a/secure/caroot/Makefile +++ b/secure/caroot/Makefile @@ -13,4 +13,5 @@ @${MAKE} -C ${.CURDIR}/trusted ${.TARGET} updatecerts: .PHONY cleancerts fetchcerts - perl ${.CURDIR}/MAca-bundle.pl -i certdata.txt -o ${.CURDIR}/trusted + perl ${.CURDIR}/MAca-bundle.pl -i certdata.txt \ + -t ${.CURDIR}/trusted -u ${.CURDIR}/untrusted diff --git a/secure/caroot/trusted/Makefile b/secure/caroot/trusted/Makefile --- a/secure/caroot/trusted/Makefile +++ b/secure/caroot/trusted/Makefile @@ -1,10 +1,10 @@ BINDIR= /usr/share/certs/trusted -TRUSTED_CERTS!= echo ${.CURDIR}/*.pem 2> /dev/null || true +TRUSTED_CERTS!= (cd ${.CURDIR} && echo *.pem) FILES+= ${TRUSTED_CERTS} -cleancerts: - @[ -z "${TRUSTED_CERTS}" ] || rm ${TRUSTED_CERTS} +cleancerts: .PHONY + @(cd ${.CURDIR} && rm -f ${TRUSTED_CERTS}) .include diff --git a/secure/caroot/untrusted/Makefile b/secure/caroot/untrusted/Makefile --- a/secure/caroot/untrusted/Makefile +++ b/secure/caroot/untrusted/Makefile @@ -1,7 +1,10 @@ BINDIR= /usr/share/certs/untrusted -UNTRUSTED_CERTS!= echo ${.CURDIR}/*.pem 2> /dev/null || true +UNTRUSTED_CERTS!= (cd ${.CURDIR} && echo *.pem) FILES+= ${UNTRUSTED_CERTS} +cleancerts: .PHONY + @(cd ${.CURDIR} && rm -f ${UNTRUSTED_CERTS}) + .include