1#!/usr/bin/perl -w 2# *************************************************************************** 3# * _ _ ____ _ 4# * Project ___| | | | _ \| | 5# * / __| | | | |_) | | 6# * | (__| |_| | _ <| |___ 7# * \___|\___/|_| \_\_____| 8# * 9# * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 10# * 11# * This software is licensed as described in the file COPYING, which 12# * you should have received as part of this distribution. The terms 13# * are also available at http://curl.haxx.se/docs/copyright.html. 14# * 15# * You may opt to use, copy, modify, merge, publish, distribute and/or sell 16# * copies of the Software, and permit persons to whom the Software is 17# * furnished to do so, under the terms of the COPYING file. 18# * 19# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20# * KIND, either express or implied. 21# * 22# *************************************************************************** 23# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. 24# It downloads certdata.txt from Mozilla's source tree (see URL below), 25# then parses certdata.txt and extracts CA Root Certificates into PEM format. 26# These are then processed with the OpenSSL commandline tool to produce the 27# final ca-bundle.crt file. 28# The script is based on the parse-certs script written by Roland Krikava. 29# This Perl script works on almost any platform since its only external 30# dependency is the OpenSSL commandline tool for optional text listing. 31# Hacked by Guenter Knauf. 32# 33use Getopt::Std; 34use MIME::Base64; 35use LWP::UserAgent; 36use strict; 37use vars qw($opt_b $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v); 38 39my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; 40# If the OpenSSL commandline is not in search path you can configure it here! 41my $openssl = 'openssl'; 42 43my $version = '1.15'; 44 45getopts('bhilnqtuv'); 46 47if ($opt_i) { 48 print ("=" x 78 . "\n"); 49 print "Script Version : $version\n"; 50 print "Perl Version : $]\n"; 51 print "Operating System Name : $^O\n"; 52 print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; 53 print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; 54 print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n"; 55 print "LWP.pm Version : ${LWP::VERSION}\n"; 56 print ("=" x 78 . "\n"); 57} 58 59$0 =~ s@.*(/|\\)@@; 60if ($opt_h) { 61 printf("Usage:\t%s [-b] [-i] [-l] [-n] [-q] [-t] [-u] [-v] [<outputfile>]\n", $0); 62 print "\t-b\tbackup an existing version of ca-bundle.crt\n"; 63 print "\t-i\tprint version info about used modules\n"; 64 print "\t-l\tprint license info about certdata.txt\n"; 65 print "\t-n\tno download of certdata.txt (to use existing)\n"; 66 print "\t-q\tbe really quiet (no progress output at all)\n"; 67 print "\t-t\tinclude plain text listing of certificates\n"; 68 print "\t-u\tunlink (remove) certdata.txt after processing\n"; 69 print "\t-v\tbe verbose and print out processed CAs\n"; 70 exit; 71} 72 73my $crt = $ARGV[0] || 'ca-bundle.crt'; 74(my $txt = $url) =~ s@(.*/|\?.*)@@g; 75 76my $resp; 77 78unless ($opt_n and -e $txt) { 79 print "Downloading '$txt' ...\n" if (!$opt_q); 80 81 my $ua = new LWP::UserAgent(agent => "$0/$version"); 82 $ua->env_proxy(); 83 $resp = $ua->mirror($url, $txt); 84} 85 86if ($resp && $resp->code eq '304') { 87 print "Not modified\n" unless $opt_q; 88 exit 0; 89} 90 91my $currentdate = scalar gmtime($resp ? $resp->last_modified : (stat($txt))[9]); 92 93if ($opt_b && -e $crt) { 94 my $bk = 1; 95 while (-e "$crt.~${bk}~") { 96 $bk++; 97 } 98 rename $crt, "$crt.~${bk}~"; 99} 100 101my $format = $opt_t ? "plain text and " : ""; 102open(CRT,">$crt") or die "Couldn't open $crt: $!"; 103print CRT <<EOT; 104## 105## $crt -- Bundle of CA Root Certificates 106## 107## Certificate data from Mozilla as of: ${currentdate} 108## 109## This is a bundle of X.509 certificates of public Certificate Authorities 110## (CA). These were automatically extracted from Mozilla's root certificates 111## file (certdata.txt). This file can be found in the mozilla source tree: 112## $url 113## 114## It contains the certificates in ${format}PEM format and therefore 115## can be directly used with curl / libcurl / php_curl, or with 116## an Apache+mod_ssl webserver for SSL client authentication. 117## Just configure this file as the SSLCACertificateFile. 118## 119 120EOT 121 122close(CRT) or die "Couldn't close $crt: $!"; 123 124print "Processing '$txt' ...\n" if (!$opt_q); 125my $caname; 126my $certnum = 0; 127open(TXT,"$txt") or die "Couldn't open $txt: $!"; 128while (<TXT>) { 129 if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { 130 open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; 131 print CRT; 132 print if ($opt_l); 133 while (<TXT>) { 134 print CRT; 135 print if ($opt_l); 136 last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); 137 } 138 close(CRT) or die "Couldn't close $crt: $!"; 139 } 140 next if /^#|^\s*$/; 141 chomp; 142 if (/^CVS_ID\s+\"(.*)\"/) { 143 open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; 144 print CRT "# $1\n"; 145 close(CRT) or die "Couldn't close $crt: $!"; 146 } 147 if (/^CKA_LABEL\s+[A-Z0-9]+\s+\"(.*)\"/) { 148 $caname = $1; 149 } 150 if (/^CKA_VALUE MULTILINE_OCTAL/) { 151 my $data; 152 while (<TXT>) { 153 last if (/^END/); 154 chomp; 155 my @octets = split(/\\/); 156 shift @octets; 157 for (@octets) { 158 $data .= chr(oct); 159 } 160 } 161 my $pem = "-----BEGIN CERTIFICATE-----\n" 162 . MIME::Base64::encode($data) 163 . "-----END CERTIFICATE-----\n"; 164 open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; 165 print CRT "\n$caname\n"; 166 print CRT ("=" x length($caname) . "\n"); 167 if (!$opt_t) { 168 print CRT $pem; 169 } 170 close(CRT) or die "Couldn't close $crt: $!"; 171 if ($opt_t) { 172 open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!"; 173 print TMP $pem; 174 close(TMP) or die "Couldn't close openssl pipe: $!"; 175 } 176 print "Parsing: $caname\n" if ($opt_v); 177 $certnum ++; 178 } 179} 180close(TXT) or die "Couldn't close $txt: $!"; 181unlink $txt if ($opt_u); 182print "Done ($certnum CA certs processed).\n" if (!$opt_q); 183 184exit; 185 186 187