3030# dependency is the OpenSSL commandline tool for optional text listing.
3131# Hacked by Guenter Knauf.
3232#
33+ use File::Basename ' dirname' ;
3334use Getopt::Std;
3435use MIME::Base64;
35- use LWP::UserAgent;
3636use strict;
37- use vars qw( $opt_b $opt_d $opt_f $ opt_h $opt_i $opt_l $opt_n $ opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w) ;
37+ use vars qw( $opt_h $opt_i $opt_l $opt_p $opt_q $opt_s $opt_t $opt_v $opt_w) ;
3838use List::Util;
3939use Text::Wrap;
40- my $MOD_SHA = " Digest::SHA" ;
41- eval " require $MOD_SHA " ;
42- if ($@ ) {
43- $MOD_SHA = " Digest::SHA::PurePerl" ;
44- eval " require $MOD_SHA " ;
45- }
46-
47- my %urls = (
48- ' nss' =>
49- ' http://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt' ,
50- ' central' =>
51- ' http://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
52- ' aurora' =>
53- ' http://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
54- ' beta' =>
55- ' http://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
56- ' release' =>
57- ' http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt' ,
58- );
59-
60- $opt_d = ' release' ;
6140
6241# If the OpenSSL commandline is not in search path you can configure it here!
6342my $openssl = ' openssl' ;
6443
6544my $version = ' 1.25' ;
6645
67- $opt_w = 76 ; # default base64 encoded lines length
46+ $opt_w = 72 ; # default base64 encoded lines length
6847
6948# default cert types to include in the output (default is to include CAs which may issue SSL server certs)
7049my $default_mozilla_trust_purposes = " SERVER_AUTH" ;
11190$Getopt::Std::STANDARD_HELP_VERSION = 1;
11291getopts(' bd:fhilnp:qs:tuvw:' );
11392
114- if (!defined ($opt_d )) {
115- # to make plain "-d" use not cause warnings, and actually still work
116- $opt_d = ' release' ;
117- }
118-
119- # Use predefined URL or else custom URL specified on command line.
120- my $url = ( defined ( $urls {$opt_d } ) ) ? $urls {$opt_d } : $opt_d ;
121-
122- my $curl = ` curl -V` ;
123-
12493if ($opt_i ) {
12594 print (" =" x 78 . " \n " );
12695 print " Script Version : $version \n " ;
12796 print " Perl Version : $] \n " ;
12897 print " Operating System Name : $^O\n " ;
12998 print " Getopt::Std.pm Version : ${Getopt::Std::VERSION} \n " ;
13099 print " MIME::Base64.pm Version : ${MIME::Base64::VERSION} \n " ;
131- print " LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION} \n " ;
132- print " LWP.pm Version : ${LWP::VERSION} \n " ;
133- print " Digest::SHA.pm Version : ${Digest::SHA::VERSION} \n " if ($Digest::SHA::VERSION );
134- print " Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION} \n " if ($Digest::SHA::PurePerl::VERSION );
135100 print (" =" x 78 . " \n " );
136101}
137102
138- sub warning_message () {
139- if ( $opt_d =~ m / ^risk$ / i ) { # Long Form Warning and Exit
140- print " Warning: Use of this script may pose some risk:\n " ;
141- print " \n " ;
142- print " 1) Using http is subject to man in the middle attack of certdata content\n " ;
143- print " 2) Default to 'release', but more recent updates may be found in other trees\n " ;
144- print " 3) certdata.txt file format may change, lag time to update this script\n " ;
145- print " 4) Generally unwise to blindly trust CAs without manual review & verification\n " ;
146- print " 5) Mozilla apps use additional security checks aren't represented in certdata\n " ;
147- print " 6) Use of this script will make a security engineer grind his teeth and\n " ;
148- print " swear at you. ;)\n " ;
149- exit ;
150- } else { # Short Form Warning
151- print " Warning: Use of this script may pose some risk, -d risk for more details.\n " ;
152- }
153- }
154-
155103sub HELP_MESSAGE () {
156- print " Usage:\t ${0} [-b] [-d<certdata>] [-f] [-i] [-l] [-n] [-p<purposes:levels>] [-q] [-s<algorithms>] [-t] [-u] [-v] [-w<l>] [<outputfile>]\n " ;
157- print " \t -b\t backup an existing version of ca-bundle.crt\n " ;
158- print " \t -d\t specify Mozilla tree to pull certdata.txt or custom URL\n " ;
159- print " \t\t Valid names are:\n " ;
160- print " \t\t " , join ( " , " , map { ( $_ =~ m /$opt_d / ) ? " $_ (default)" : " $_ " } sort keys %urls ), " \n " ;
161- print " \t -f\t force rebuild even if certdata.txt is current\n " ;
104+ print " Usage:\t ${0} [-i] [-l] [-p<purposes:levels>] [-q] [-s<algorithms>] [-t] [-v] [-w<l>] [<outputfile>]\n " ;
162105 print " \t -i\t print version info about used modules\n " ;
163106 print " \t -l\t print license info about certdata.txt\n " ;
164- print " \t -n\t no download of certdata.txt (to use existing)\n " ;
165107 print wrap(" \t " ," \t\t " , " -p\t list of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes :$default_mozilla_trust_levels )" ), " \n " ;
166108 print " \t\t Valid purposes are:\n " ;
167109 print wrap(" \t\t " ," \t\t " , join ( " , " , " ALL" , @valid_mozilla_trust_purposes ) ), " \n " ;
172114 print " \t\t Valid signature algorithms are:\n " ;
173115 print wrap(" \t\t " ," \t\t " , join ( " , " , " ALL" , @valid_signature_algorithms ) ), " \n " ;
174116 print " \t -t\t include plain text listing of certificates\n " ;
175- print " \t -u\t unlink (remove) certdata.txt after processing\n " ;
176117 print " \t -v\t be verbose and print out processed CAs\n " ;
177118 print " \t -w <l>\t wrap base64 output lines after <l> chars (default: ${opt_w} )\n " ;
178119 exit ;
182123 print " ${0} version ${version} running Perl ${]} on ${^O}\n " ;
183124}
184125
185- warning_message() unless ($opt_q || $url =~ m / ^(ht|f)tps:/ i );
186126HELP_MESSAGE() if ($opt_h );
187127
188128sub report ($@) {
@@ -224,35 +164,6 @@ ($$@)
224164 return @values ;
225165}
226166
227- sub sha1 {
228- my $result ;
229- if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION ) {
230- open (FILE, $_ [0]) or die " Can't open '$_ [0]': $! " ;
231- binmode (FILE);
232- $result = $MOD_SHA -> new(1)-> addfile(*FILE)-> hexdigest;
233- close (FILE);
234- } else {
235- # Use OpenSSL command if Perl Digest::SHA modules not available
236- $result = (split (/ |\r |\n / ,` $openssl dgst -sha1 $_ [0]` ))[1];
237- }
238- return $result ;
239- }
240-
241-
242- sub oldsha1 {
243- my $sha1 = " " ;
244- open (C, " <$_ [0]" ) || return 0;
245- while (<C>) {
246- chomp ;
247- if ($_ =~ / ^\#\# SHA1: (.*)/ ) {
248- $sha1 = $1 ;
249- last ;
250- }
251- }
252- close (C);
253- return $sha1 ;
254- }
255-
256167if ( $opt_p !~ m / :/ ) {
257168 print " Error: Mozilla trust identifier list must include both purposes and levels\n " ;
258169 HELP_MESSAGE();
@@ -275,98 +186,17 @@ (%)
275186 return 0;
276187}
277188
278- my $crt = $ARGV [0] || ' ca-bundle.crt ' ;
279- ( my $txt = $url ) =~ s @ (.*/| \? .*) @@ g ;
189+ my $crt = $ARGV [0] || dirname( __FILE__ ) . ' /../src/node_root_certs.h ' ;
190+ my $txt = dirname( __FILE__ ) . ' /certdata.txt ' ;
280191
281192my $stdout = $crt eq ' -' ;
282- my $resp ;
283- my $fetched ;
284-
285- my $oldsha1 = oldsha1($crt );
286193
287- report " SHA1 of old file: $oldsha1 " ;
288-
289- report " Downloading '$txt ' ..." ;
290-
291- if ($curl && !$opt_n ) {
292- my $https = $url ;
293- $https =~ s / ^http:/ https:/ ;
294- report " Get certdata over HTTPS with curl!" ;
295- my $quiet = $opt_q ? " -s" : " " ;
296- my @out = ` curl -w %{response_code} $quiet -O $https ` ;
297- if (@out && $out [0] == 200) {
298- $fetched = 1;
299- } else {
300- report " Failed downloading HTTPS with curl, trying HTTP with LWP" ;
301- }
302- }
303-
304- unless ($fetched || ($opt_n and -e $txt )) {
305- my $ua = new LWP::UserAgent(agent => " $0 /$version " );
306- $ua -> env_proxy();
307- $resp = $ua -> mirror($url , $txt );
308- if ($resp && $resp -> code eq ' 304' ) {
309- report " Not modified" ;
310- exit 0 if -e $crt && !$opt_f ;
311- } else {
312- $fetched = 1;
313- }
314- if ( !$resp || $resp -> code !~ / ^(?:200|304)$ / ) {
315- report " Unable to download latest data: "
316- . ($resp ? $resp -> code . ' - ' . $resp -> message : " LWP failed" );
317- exit 1 if -e $crt || ! -r $txt ;
318- }
319- }
320-
321- my $filedate = $resp ? $resp -> last_modified : (stat ($txt ))[9];
322- my $datesrc = " as of" ;
323- if (!$filedate ) {
324- # mxr.mozilla.org gave us a time, hg.mozilla.org does not!
325- $filedate = time ();
326- $datesrc =" downloaded on" ;
327- }
328-
329- # get the hash from the download file
330- my $newsha1 = sha1($txt );
331-
332- if (!$opt_f && $oldsha1 eq $newsha1 ) {
333- report " Downloaded file identical to previous run\' s source file. Exiting" ;
334- exit ;
335- }
336-
337- report " SHA1 of new file: $newsha1 " ;
338-
339- my $currentdate = scalar gmtime ($filedate );
340-
341- my $format = $opt_t ? " plain text and " : " " ;
342194if ( $stdout ) {
343195 open (CRT, ' > -' ) or die " Couldn't open STDOUT: $! \n " ;
344196} else {
345197 open (CRT," >$crt .~" ) or die " Couldn't open $crt .~: $! \n " ;
346198}
347- print CRT <<EOT ;
348- ##
349- ## Bundle of CA Root Certificates
350- ##
351- ## Certificate data from Mozilla ${datesrc} : ${currentdate}
352- ##
353- ## This is a bundle of X.509 certificates of public Certificate Authorities
354- ## (CA). These were automatically extracted from Mozilla's root certificates
355- ## file (certdata.txt). This file can be found in the mozilla source tree:
356- ## ${url}
357- ##
358- ## It contains the certificates in ${format} PEM format and therefore
359- ## can be directly used with curl / libcurl / php_curl, or with
360- ## an Apache+mod_ssl webserver for SSL client authentication.
361- ## Just configure this file as the SSLCACertificateFile.
362- ##
363- ## Conversion done with mk-ca-bundle.pl version $version .
364- ## SHA1: $newsha1
365- ##
366-
367- EOT
368-
369- report " Processing '$txt ' ..." ;
199+
370200my $caname ;
371201my $certnum = 0;
372202my $skipnum = 0;
386216 next if / ^#|^\s *$ / ;
387217 chomp ;
388218 if (/ ^CVS_ID\s +\" (.*)\" / ) {
389- print CRT " # $1 \n " ;
219+ print CRT " /* $1 */ \n " ;
390220 }
391221
392222 # this is a match for the start of a certificate
@@ -431,11 +261,11 @@ (%)
431261 $skipnum ++;
432262 } else {
433263 my $encoded = MIME::Base64::encode_base64($data , ' ' );
434- $encoded =~ s / (.{1,${opt_w}})/ $1 \n / g ;
435- my $pem = " -----BEGIN CERTIFICATE-----\n "
264+ $encoded =~ s / (.{1,${opt_w}})/ " $1 \\ n" \n / g ;
265+ my $pem = " \" -----BEGIN CERTIFICATE-----\\ n \" \n"
436266 . $encoded
437- . " -----END CERTIFICATE-----\n " ;
438- print CRT " \n $caname \n " ;
267+ . " \" -----END CERTIFICATE-----\\ n \" , \n " ;
268+ print CRT " \n /* $caname */ \n " ;
439269
440270 my $maxStringLength = length ($caname );
441271 if ($opt_t ) {
445275 print CRT $string . " \n " ;
446276 }
447277 }
448- print CRT (" =" x $maxStringLength . " \n " );
449278 if (!$opt_t ) {
450279 print CRT $pem ;
451280 } else {
484313close (TXT) or die " Couldn't close $txt : $! \n " ;
485314close (CRT) or die " Couldn't close $crt .~: $! \n " ;
486315unless ( $stdout ) {
487- if ($opt_b && -e $crt ) {
488- my $bk = 1;
489- while (-e " $crt .~${bk} ~" ) {
490- $bk ++;
491- }
492- rename $crt , " $crt .~${bk} ~" or die " Failed to create backup $crt .~$bk }~: $! \n " ;
493- } elsif ( -e $crt ) {
494- unlink ( $crt ) or die " Failed to remove $crt : $! \n " ;
495- }
496316 rename " $crt .~" , $crt or die " Failed to rename $crt .~ to $crt : $! \n " ;
497317}
498- unlink $txt if ($opt_u );
499318report " Done ($certnum CA certs processed, $skipnum skipped)." ;
0 commit comments