Index: security/ca_root_nss/files/MAca-bundle.pl.in =================================================================== --- security/ca_root_nss/files/MAca-bundle.pl.in +++ security/ca_root_nss/files/MAca-bundle.pl.in @@ -1,3 +1,4 @@ +#!/usr/bin/env perl ## ## MAca-bundle.pl -- Regenerate ca-root-nss.crt from the Mozilla certdata.txt ## @@ -6,6 +7,7 @@ ## Copyright (c) 2011, 2013 Matthias Andree ## All rights reserved. +## Copyright (c) 2018, Allan Jude ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are @@ -34,12 +36,52 @@ 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; -# configuration -print < \$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 <) { + while (<$ifh>) { last if /^END/; my (undef,@oct) = split /\\/; my @bin = map(chr(oct), @oct); @@ -98,13 +121,14 @@ } -sub grabcert() +sub grabcert($) { + my $ifh = shift; my $certdata; my $cka_label; my $serial; - while (<>) { + while (<$ifh>) { chomp; last if ($_ eq ''); @@ -113,23 +137,24 @@ } if (/^CKA_VALUE MULTILINE_OCTAL/) { - $certdata = graboct(); + $certdata = graboct($ifh); } if (/^CKA_SERIAL_NUMBER MULTILINE_OCTAL/) { - $serial = graboct(); + $serial = graboct($ifh); } } return ($serial, $cka_label, $certdata); } -sub grabtrust() { +sub grabtrust($) { + my $ifh = shift; my $cka_label; my $serial; my $maytrust = 0; my $distrust = 0; - while (<>) { + while (<$ifh>) { chomp; last if ($_ eq ''); @@ -138,7 +163,7 @@ } if (/^CKA_SERIAL_NUMBER MULTILINE_OCTAL/) { - $serial = graboct(); + $serial = graboct($ifh); } if (/^CKA_TRUST_(SERVER_AUTH|EMAIL_PROTECTION|CODE_SIGNING) CK_TRUST (\S+)$/) @@ -163,27 +188,37 @@ return ($serial, $cka_label, $trust); } -while (<>) { +if (!$outputdir) { + print_header(*STDOUT, ""); +} + +while (<$inputfh>) { if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { - my ($serial, $label, $certdata) = grabcert(); + 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(); + 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 printlabel(@) { +sub label_to_filename(@) { my @res = @_; - map { s/\0.*//; s/[^[:print:]]/_/g; $_ = "\"$_\""; } @res; + map { s/\0.*//; s/[^[:alnum:]\-]/_/g; $_ = "$_.pem"; } @res; return wantarray ? @res : $res[0]; } @@ -192,33 +227,48 @@ foreach my $it (keys %trusts) { if (!$trusts{$it}) { if (!exists($certs{$it})) { - warn "Found trust for nonexistent certificate ".printlabel($it)."\n" if $debug; + warn "Found trust for nonexistent certificate $labels{$it}\n" if $debug; } else { delete $certs{$it}; - warn "Skipping untrusted ".printlabel($it)."\n" if $debug; + warn "Skipping untrusted $labels{$it}\n" if $debug; $untrusted++; } } } -print "## Untrusted certificates omitted from this bundle: $untrusted\n\n"; +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"; } - printcert("", $certs{$it}); - print "\n\n\n"; + 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: ".printlabel($it)."\n" if $debug; + print STDERR "Trusting $certcount: $labels{$it}\n" if $debug; } if ($certcount < 25) { die "Certificate count of $certcount is implausibly low.\nAbort"; } -print "## Number of certificates: $certcount\n"; +if (!$outputdir) { + print "## Number of certificates: $certcount\n"; + print "## End of file.\n"; +} print STDERR "## Number of certificates: $certcount\n"; -print "## End of file.\n";