Skip to content

Instantly share code, notes, and snippets.

@arnested
Created February 23, 2012 19:00
Show Gist options
  • Save arnested/1894381 to your computer and use it in GitHub Desktop.
Save arnested/1894381 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# Copyright (C) 2004, 2005 by Arne Jørgensen
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
use strict;
$^W=1; # turn warning on
use Getopt::Long;
use Cwd qw( abs_path );
use LWP::UserAgent;
use Date::Parse;
use File::Temp qw/ :POSIX /;
use File::Copy;
use File::Compare;
use IO::Handle;
my $openssl = "openssl";
my $errorlevel = 1;
my @CApath = ();
my @CAcerts = ();
GetOptions("CApath=s" => \@CApath,
"openssl:s" => \$openssl,
"errorlevel:i" => \$errorlevel,
);
IO::Handle->autoflush();
scan_capaths();
scan_cacerts();
show_cacerts();
#download_crl();
sub scan_capaths {
msglog(2, "Scaninng CApaths...");
foreach my $dir ( @CApath ) {
my $absdir = abs_path($dir);
msglog(3, "Scanning CApath: $absdir...");
opendir (DIR, $absdir) || msglog(0, "Unable to read CApath: $absdir.");
my @certs = grep { /.*\.\d+/ } readdir (DIR);
close (DIR);
foreach my $CAfile (@certs) {
my $certinfo = {absdir => $absdir,
CAfile => $CAfile,
};
push @CAcerts, $certinfo;
msglog(3, "Found (possible) CA-certificate: $CAfile");
};
};
msglog(3, "Scanning CApaths... done.");
};
sub scan_cacerts {
msglog(2, "Scaninng CA-certificates...");
foreach my $certinfo ( @CAcerts ) {
msglog(3, "Scanning CA-cert: " . $certinfo->{CAfile} );
scan_cacert( $certinfo );
};
msglog(2, "Scaninng CA-certificates... done.");
};
sub scan_cacert {
my $certinfo = $_[0];
my $crl_dist_point = 0;
my $validity = 0;
open (OPENSSL, "$openssl x509 -in " . $certinfo->{absdir} . "/" . $certinfo->{CAfile} . " -noout -text |") || {$certinfo->{badcert} = 1};
while (<OPENSSL>) {
chomp;
$certinfo->{badcert} = 0;
if ( $_ =~ /Validity/ and $validity == 0 ) {
$validity++;
};
if ( $_ =~ /Not Before:/ and $validity > 0 and $validity < 3 ) {
$certinfo->{notbefore} = str2time( ${ [split (/:/, $_, 2)] }[1] );
$validity++;
};
if ( $_ =~ /Not After :/ and $validity > 0 and $validity < 3 ) {
$certinfo->{notafter} = str2time( ${ [split(/:/, $_, 2) ]}[1] );
$validity++;
};
if ( $_ =~ /X509v3 CRL Distribution Points:/ ) {
$crl_dist_point = 1;
};
if ( $crl_dist_point eq 1 and $_ =~ /^$/ ) {
$crl_dist_point = 0;
};
if ( $crl_dist_point eq 1 and $_ =~ /URI:/ ) {
chomp;
$certinfo->{crluri} = ${ [split(/:/, $_, 2)] }[1];
};
if ( $_ =~ /Issuer:/ ) {
$certinfo->{issuer} = ${ [split(/:/, $_, 2)] }[1];
msglog(4, "Issuer: " . $certinfo->{issuer});
};
};
close OPENSSL;
};
sub show_cacerts {
msglog(2, "Downloading CRL's...");
foreach my $certinfo ( @CAcerts ) {
if (defined $certinfo->{badcert} && $certinfo->{badcert}) {
next;
} elsif (not defined $certinfo->{crluri}) {
msglog(1, $certinfo->{CAfile} . " has no CRL Distribution Point");
} else {
download_crl( $certinfo );
};
};
msglog(2, "Downloading CRL's... done.");
};
sub download_crl {
my $certinfo = $_[0];
my $ua = LWP::UserAgent->new();
my $time = time;
my $absCAfile = $certinfo->{absdir} . "/" . $certinfo->{CAfile};
if ( $time < $certinfo->{notbefore} ) {
msglog(1, "$absCAfile: too new.\n");
} elsif ( $time > $certinfo->{notafter} ) {
msglog(0, "$absCAfile: too old.\n");
} else {
(my $crlfile = $absCAfile) =~ s/(.*\.)(\d+)/$1r$2/;
my ($tmpfh, $tmpfile) = tmpnam();
msglog(2, "Downloading " . $certinfo->{CAfile} . " / " . $certinfo->{crluri} . "...");
my $response = $ua->get( $certinfo->{crluri} );
if ($response->is_success) {
msglog(2, "Downloading " . $certinfo->{CAfile} . " / " . $certinfo->{crluri} . "... " . $response->status_line);
if ( $response->content =~ /-----BEGIN X509 CRL-----/ ) {
printf $tmpfh $response->content;
} else {
open(OPENSSL, "| $openssl crl -inform DER -outform PEM -out $tmpfile");
print OPENSSL $response->content;
close OPENSSL;
};
open (OPENSSL, "$openssl crl -in $tmpfile -inform PEM -noout -CAfile $absCAfile 2>&1 |");
while (<OPENSSL>) {
if ($_ =~ /verify OK/) {
if ( -e $crlfile ) {
if ( compare( $tmpfile, $crlfile) == 0 ) {
msglog(1, $certinfo->{CAfile} . " / " . $certinfo->{crluri} . " is equal to present CRL.");
} else {
move( $crlfile, make_backup_filename($crlfile) );
move( $tmpfile, $crlfile );
}
} else {
move( $tmpfile, $crlfile );
};
chmod 0644, $crlfile;
} else {
msglog(0, $certinfo->{CAfile} . " CRL does not verify!");
};
};
close OPENSSL;
unlink $tmpfile;
} else {
msglog(0, "Downloading " . $certinfo->{CAfile} . " / " . $certinfo->{crluri} . "... " . $response->status_line);
};
};
};
sub make_backup_filename {
return $_[0] . "~";
};
sub msglog {
my ($level, $msg) = @_;
printf STDERR $msg . "\n" unless $level >= $errorlevel;
};
# crl-update ends here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment