@@ -32,9 +32,8 @@
#
use Getopt::Std;
use MIME::Base64;
use LWP::UserAgent;
use strict;
use vars qw( $opt_b $opt_d $opt_f $opt_h $opt_i $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w) ;
use vars qw( $opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $ opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w) ;
use List::Util;
use Text::Wrap;
my $MOD_SHA = " Digest::SHA" ;
@@ -43,26 +42,27 @@
$MOD_SHA = " Digest::SHA::PurePerl" ;
eval " require $MOD_SHA " ;
}
eval " require LWP::UserAgent" ;
my %urls = (
' nss' =>
' http ://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt' ,
' https ://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt' ,
' central' =>
' http ://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' https ://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' aurora' =>
' http ://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' https ://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' beta' =>
' http ://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' https ://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' release' =>
' http ://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
' https ://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
);
$opt_d = ' release' ;
# If the OpenSSL commandline is not in search path you can configure it here!
my $openssl = ' openssl' ;
my $version = ' 1.26 ' ;
my $version = ' 1.27 ' ;
$opt_w = 76; # default base64 encoded lines length
@@ -109,15 +109,24 @@
$0 =~ s @ .*(/|\\ )@@ ;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
getopts(' bd:fhilmnp :qs:tuvw:' );
getopts(' bd:fhiklmnp :qs:tuvw:' );
if (!defined ($opt_d )) {
# to make plain "-d" use not cause warnings, and actually still work
$opt_d = ' release' ;
}
# Use predefined URL or else custom URL specified on command line.
my $url = ( defined ( $urls {$opt_d } ) ) ? $urls {$opt_d } : $opt_d ;
my $url ;
if (defined ($urls {$opt_d })) {
$url = $urls {$opt_d };
if (!$opt_k && $url !~ / ^https:\/\/ /i ) {
die " The URL for '$opt_d ' is not HTTPS. Use -k to override (insecure).\n " ;
}
}
else {
$url = $opt_d ;
}
my $curl = ` curl -V` ;
@@ -128,8 +137,8 @@
print " Operating System Name : $^O\n " ;
print " Getopt::Std.pm Version : ${Getopt::Std::VERSION} \n " ;
print " MIME::Base64.pm Version : ${MIME::Base64::VERSION} \n " ;
print " LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION} \n " ;
print " LWP.pm Version : ${LWP::VERSION} \n " ;
print " LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION} \n " if ( $LWP::UserAgent::VERSION ) ;
print " LWP.pm Version : ${LWP::VERSION} \n " if ( $LWP::VERSION ) ;
print " Digest::SHA.pm Version : ${Digest::SHA::VERSION} \n " if ($Digest::SHA::VERSION );
print " Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION} \n " if ($Digest::SHA::PurePerl::VERSION );
print (" =" x 78 . " \n " );
@@ -139,7 +148,7 @@ ()
if ( $opt_d =~ m / ^risk$ / i ) { # Long Form Warning and Exit
print " Warning: Use of this script may pose some risk:\n " ;
print " \n " ;
print " 1) Using http is subject to man in the middle attack of certdata content \n " ;
print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n " ;
print " 2) Default to 'release', but more recent updates may be found in other trees\n " ;
print " 3) certdata.txt file format may change, lag time to update this script\n " ;
print " 4) Generally unwise to blindly trust CAs without manual review & verification\n " ;
@@ -153,13 +162,14 @@ ()
}
sub HELP_MESSAGE () {
print " Usage:\t ${0} [-b] [-d<certdata>] [-f] [-i] [-l] [-n] [-p<purposes:levels>] [-q] [-s<algorithms>] [-t] [-u] [-v] [-w<l>] [<outputfile>]\n " ;
print " Usage:\t ${0} [-b] [-d<certdata>] [-f] [-i] [-k] [- l] [-n] [-p<purposes:levels>] [-q] [-s<algorithms>] [-t] [-u] [-v] [-w<l>] [<outputfile>]\n " ;
print " \t -b\t backup an existing version of ca-bundle.crt\n " ;
print " \t -d\t specify Mozilla tree to pull certdata.txt or custom URL\n " ;
print " \t\t Valid names are:\n " ;
print " \t\t " , join ( " , " , map { ( $_ =~ m /$opt_d / ) ? " $_ (default)" : " $_ " } sort keys %urls ), " \n " ;
print " \t -f\t force rebuild even if certdata.txt is current\n " ;
print " \t -i\t print version info about used modules\n " ;
print " \t -k\t allow URLs other than HTTPS, enable HTTP fallback (insecure)\n " ;
print " \t -l\t print license info about certdata.txt\n " ;
print " \t -m\t include meta data in output\n " ;
print " \t -n\t no download of certdata.txt (to use existing)\n " ;
@@ -287,35 +297,68 @@ (%)
report " SHA256 of old file: $oldhash " ;
report " Downloading '$txt ' ..." ;
if ($curl && !$opt_n ) {
my $https = $url ;
$https =~ s / ^http:/ https:/ ;
report " Get certdata over HTTPS with curl!" ;
my $quiet = $opt_q ? " -s" : " " ;
my @out = ` curl -w %{response_code} $quiet -O $https ` ;
if (@out && $out [0] == 200) {
$fetched = 1;
} else {
report " Failed downloading HTTPS with curl, trying HTTP with LWP" ;
if (!$opt_n ) {
report " Downloading $txt ..." ;
# If we have an HTTPS URL then use curl
if ($url =~ / ^https:\/\/ /i ) {
if ($curl ) {
if ($curl =~ / ^Protocols:.* https( |$) /m ) {
report " Get certdata with curl!" ;
my $proto = !$opt_k ? " --proto =https" : " " ;
my $quiet = $opt_q ? " -s" : " " ;
my @out = ` curl -w %{response_code} $proto $quiet -o "$txt " "$url "` ;
if (@out && $out [0] == 200) {
$fetched = 1;
report " Downloaded $txt " ;
}
else {
report " Failed downloading via HTTPS with curl" ;
if (-e $txt && !unlink ($txt )) {
report " Failed to remove '$txt ': $! " ;
}
}
}
else {
report " curl lacks https support" ;
}
}
else {
report " curl not found" ;
}
}
}
unless ($fetched || ($opt_n and -e $txt )) {
my $ua = new LWP::UserAgent(agent => " $0 /$version " );
$ua -> env_proxy();
$resp = $ua -> mirror($url , $txt );
if ($resp && $resp -> code eq ' 304' ) {
report " Not modified" ;
exit 0 if -e $crt && !$opt_f ;
} else {
# If nothing was fetched then use LWP
if (!$fetched ) {
if ($url =~ / ^https:\/\/ /i ) {
report " Falling back to HTTP" ;
$url =~ s / ^https:\/\/ / http:\/\/ / i ;
}
if (!$opt_k ) {
report " URLs other than HTTPS are disabled by default, to enable use -k" ;
exit 1;
}
report " Get certdata with LWP!" ;
if (!defined (${LWP::UserAgent::VERSION} )) {
report " LWP is not available (LWP::UserAgent not found)" ;
exit 1;
}
my $ua = new LWP::UserAgent(agent => " $0 /$version " );
$ua -> env_proxy();
$resp = $ua -> mirror($url , $txt );
if ($resp && $resp -> code eq ' 304' ) {
report " Not modified" ;
exit 0 if -e $crt && !$opt_f ;
}
else {
$fetched = 1;
}
if ( !$resp || $resp -> code !~ / ^(?:200|304)$ / ) {
report " Downloaded $txt " ;
}
if (!$resp || $resp -> code !~ / ^(?:200|304)$ / ) {
report " Unable to download latest data: "
. ($resp ? $resp -> code . ' - ' . $resp -> message : " LWP failed" );
exit 1 if -e $crt || ! -r $txt ;
}
}
}
@@ -503,5 +546,7 @@ (%)
}
rename " $crt .~" , $crt or die " Failed to rename $crt .~ to $crt : $! \n " ;
}
unlink $txt if ($opt_u );
if ($opt_u && -e $txt && !unlink ($txt )) {
report " Failed to remove $txt : $! \n " ;
}
report " Done ($certnum CA certs processed, $skipnum skipped)." ;