diff options
Diffstat (limited to 'lib/mk-ca-bundle.pl')
-rwxr-xr-x | lib/mk-ca-bundle.pl | 171 |
1 files changed, 113 insertions, 58 deletions
diff --git a/lib/mk-ca-bundle.pl b/lib/mk-ca-bundle.pl index 3586dc468..1a9c85985 100755 --- a/lib/mk-ca-bundle.pl +++ b/lib/mk-ca-bundle.pl @@ -6,7 +6,7 @@ # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * -# * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. +# * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. # * # * This software is licensed as described in the file COPYING, which # * you should have received as part of this distribution. The terms @@ -34,15 +34,19 @@ use Getopt::Std; use MIME::Base64; use LWP::UserAgent; use strict; -use vars qw($opt_b $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v); +use vars qw($opt_b $opt_f $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v $opt_w); -my $url = 'http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; +my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; -my $version = '1.14'; +my $version = '1.19'; -getopts('bhilnqtuv'); +$opt_w = 76; # default base64 encoded lines length + +$0 =~ s@.*(/|\\)@@; +$Getopt::Std::STANDARD_HELP_VERSION = 1; +getopts('bfhilnqtuvw:'); if ($opt_i) { print ("=" x 78 . "\n"); @@ -56,11 +60,10 @@ if ($opt_i) { print ("=" x 78 . "\n"); } -$0 =~ s/\\/\//g; -$0 = substr($0, rindex($0, '/') + 1); -if ($opt_h) { - printf("Usage:\t%s [-b] [-i] [-l] [-n] [-q] [-t] [-u] [-v] [<outputfile>]\n", $0); +sub HELP_MESSAGE() { + print "Usage:\t${0} [-b] [-f] [-i] [-l] [-n] [-q] [-t] [-u] [-v] [-w<l>] [<outputfile>]\n"; print "\t-b\tbackup an existing version of ca-bundle.crt\n"; + print "\t-f\tforce rebuild even if certdata.txt is current\n"; print "\t-i\tprint version info about used modules\n"; print "\t-l\tprint license info about certdata.txt\n"; print "\t-n\tno download of certdata.txt (to use existing)\n"; @@ -68,48 +71,60 @@ if ($opt_h) { print "\t-t\tinclude plain text listing of certificates\n"; print "\t-u\tunlink (remove) certdata.txt after processing\n"; print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w <l>\twrap base64 output lines after <l> chars (default: ${opt_w})\n"; exit; } +sub VERSION_MESSAGE() { + print "${0} version ${version} running Perl ${]} on ${^O}\n"; +} + +HELP_MESSAGE() if ($opt_h); + my $crt = $ARGV[0] || 'ca-bundle.crt'; -my $txt = substr($url, rindex($url, '/') + 1); -$txt =~ s/\?.*//; +(my $txt = $url) =~ s@(.*/|\?.*)@@g; + +my $stdout = $crt eq '-'; +my $resp; +my $fetched; -if (!$opt_n || !-e $txt) { - print "Downloading '$txt' ...\n" if (!$opt_q); +unless ($opt_n and -e $txt) { + print STDERR "Downloading '$txt' ...\n" if (!$opt_q); my $ua = new LWP::UserAgent(agent => "$0/$version"); - my $req = new HTTP::Request('GET', $url); - my $res = $ua->request($req); - if ($res->is_success) { - open(TXT,">$txt") or die "Couldn't open $txt: $!"; - print TXT $res->content . "\n"; - close(TXT) or die "Couldn't close $txt: $!"; + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if ($resp && $resp->code eq '304') { + print STDERR "Not modified\n" unless $opt_q; + exit 0 if -e $crt && !$opt_f; } else { - die $res->status_line; + $fetched = 1; } -} - -if ($opt_b && -e $crt) { - my $bk = 1; - while (-e "$crt.~${bk}~") { - $bk++; + if( !$resp || $resp->code !~ /^(?:200|304)$/ ) { + print STDERR "Unable to download latest data: " + . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed") . "\n" + unless $opt_q; + exit 1 if -e $crt || ! -r $txt; } - rename $crt, "$crt.~${bk}~"; } +my $currentdate = scalar gmtime($fetched ? $resp->last_modified : (stat($txt))[9]); + my $format = $opt_t ? "plain text and " : ""; -my $currentdate = scalar gmtime() . " UTC"; -open(CRT,">$crt") or die "Couldn't open $crt: $!"; +if( $stdout ) { + open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; +} else { + open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; +} print CRT <<EOT; ## ## $crt -- Bundle of CA Root Certificates ## -## Converted at: ${currentdate} +## Certificate data from Mozilla as of: ${currentdate} ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: -## '/mozilla/security/nss/lib/ckfw/builtins/certdata.txt' +## ${url} ## ## It contains the certificates in ${format}PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with @@ -119,15 +134,15 @@ print CRT <<EOT; EOT -close(CRT) or die "Couldn't close $crt: $!"; - -print "Processing '$txt' ...\n" if (!$opt_q); +print STDERR "Processing '$txt' ...\n" if (!$opt_q); my $caname; my $certnum = 0; -open(TXT,"$txt") or die "Couldn't open $txt: $!"; +my $skipnum = 0; +my $start_of_cert = 0; + +open(TXT,"$txt") or die "Couldn't open $txt: $!\n"; while (<TXT>) { if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { - open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; print CRT; print if ($opt_l); while (<TXT>) { @@ -135,19 +150,22 @@ while (<TXT>) { print if ($opt_l); last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); } - close(CRT) or die "Couldn't close $crt: $!"; } next if /^#|^\s*$/; chomp; if (/^CVS_ID\s+\"(.*)\"/) { - open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; print CRT "# $1\n"; - close(CRT) or die "Couldn't close $crt: $!"; } - if (/^CKA_LABEL\s+[A-Z0-9]+\s+\"(.*)\"/) { + + # this is a match for the start of a certificate + if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + $start_of_cert = 1 + } + if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { $caname = $1; } - if (/^CKA_VALUE MULTILINE_OCTAL/) { + my $untrusted = 1; + if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { my $data; while (<TXT>) { last if (/^END/); @@ -158,28 +176,65 @@ while (<TXT>) { $data .= chr(oct); } } - my $pem = "-----BEGIN CERTIFICATE-----\n" - . MIME::Base64::encode($data) - . "-----END CERTIFICATE-----\n"; - open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; - print CRT "\n$caname\n"; - print CRT ("=" x length($caname) . "\n"); - if (!$opt_t) { - print CRT $pem; + # scan forwards until the trust part + while (<TXT>) { + last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); + chomp; + } + # now scan the trust part for untrusted certs + while (<TXT>) { + last if (/^#/); + if (/^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_TRUSTED_DELEGATOR$/) { + $untrusted = 0; + } } - close(CRT) or die "Couldn't close $crt: $!"; - if ($opt_t) { - open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; + if ($untrusted) { + $skipnum ++; + } else { + my $encoded = MIME::Base64::encode_base64($data, ''); + $encoded =~ s/(.{1,${opt_w}})/$1\n/g; + my $pem = "-----BEGIN CERTIFICATE-----\n" + . $encoded + . "-----END CERTIFICATE-----\n"; + print CRT "\n$caname\n"; + print CRT ("=" x length($caname) . "\n"); + if (!$opt_t) { + print CRT $pem; + } else { + my $pipe = "|$openssl x509 -md5 -fingerprint -text -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + print STDERR "Parsing: $caname\n" if ($opt_v); + $certnum ++; + $start_of_cert = 0; } - print "Parsing: $caname\n" if ($opt_v); - $certnum ++; } } -close(TXT) or die "Couldn't close $txt: $!"; +close(TXT) or die "Couldn't close $txt: $!\n"; +close(CRT) or die "Couldn't close $crt.~: $!\n"; +unless( $stdout ) { + if ($opt_b && -e $crt) { + my $bk = 1; + while (-e "$crt.~${bk}~") { + $bk++; + } + rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; + } elsif( -e $crt ) { + unlink( $crt ) or die "Failed to remove $crt: $!\n"; + } + rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; +} unlink $txt if ($opt_u); -print "Done ($certnum CA certs processed).\n" if (!$opt_q); +print STDERR "Done ($certnum CA certs processed, $skipnum untrusted skipped).\n" if (!$opt_q); exit; |