1167612Ssimon#!/usr/bin/perl 255714Skris 355714Skris 468651Skris# Perl c_rehash script, scan all files in a directory 568651Skris# and add symbolic links to their hash values. 655714Skris 768651Skrismy $openssl; 855714Skris 968651Skrismy $dir = "/usr/local/ssl"; 10215697Ssimonmy $prefix = "/usr/local/ssl"; 1155714Skris 1268651Skrisif(defined $ENV{OPENSSL}) { 1368651Skris $openssl = $ENV{OPENSSL}; 1468651Skris} else { 1568651Skris $openssl = "openssl"; 1668651Skris $ENV{OPENSSL} = $openssl; 1768651Skris} 1868651Skris 1968651Skris$ENV{PATH} .= ":$dir/bin"; 2068651Skris 21109998Smarkmif(! -x $openssl) { 2268651Skris my $found = 0; 2368651Skris foreach (split /:/, $ENV{PATH}) { 24109998Smarkm if(-x "$_/$openssl") { 2568651Skris $found = 1; 2668651Skris last; 2768651Skris } 2868651Skris } 2968651Skris if($found == 0) { 3068651Skris print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n"; 3168651Skris exit 0; 3268651Skris } 3368651Skris} 3468651Skris 3568651Skrisif(@ARGV) { 3668651Skris @dirlist = @ARGV; 3768651Skris} elsif($ENV{SSL_CERT_DIR}) { 3868651Skris @dirlist = split /:/, $ENV{SSL_CERT_DIR}; 3968651Skris} else { 4068651Skris $dirlist[0] = "$dir/certs"; 4168651Skris} 4268651Skris 4368651Skris 4468651Skrisforeach (@dirlist) { 4568651Skris if(-d $_ and -w $_) { 4668651Skris hash_dir($_); 4768651Skris } 4868651Skris} 4968651Skris 5068651Skrissub hash_dir { 5168651Skris my %hashlist; 5268651Skris print "Doing $_[0]\n"; 5368651Skris chdir $_[0]; 5468651Skris opendir(DIR, "."); 5568651Skris my @flist = readdir(DIR); 5668651Skris # Delete any existing symbolic links 5768651Skris foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { 5868651Skris if(-l $_) { 5968651Skris unlink $_; 6068651Skris } 6168651Skris } 6268651Skris closedir DIR; 6368651Skris FILE: foreach $fname (grep {/\.pem$/} @flist) { 6468651Skris # Check to see if certificates and/or CRLs present. 6568651Skris my ($cert, $crl) = check_file($fname); 6668651Skris if(!$cert && !$crl) { 6768651Skris print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; 6868651Skris next; 6968651Skris } 7068651Skris link_hash_cert($fname) if($cert); 7168651Skris link_hash_crl($fname) if($crl); 7268651Skris } 7368651Skris} 7468651Skris 7568651Skrissub check_file { 7668651Skris my ($is_cert, $is_crl) = (0,0); 7768651Skris my $fname = $_[0]; 7868651Skris open IN, $fname; 7968651Skris while(<IN>) { 8068651Skris if(/^-----BEGIN (.*)-----/) { 8168651Skris my $hdr = $1; 8268651Skris if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) { 8368651Skris $is_cert = 1; 8468651Skris last if($is_crl); 8568651Skris } elsif($hdr eq "X509 CRL") { 8668651Skris $is_crl = 1; 8768651Skris last if($is_cert); 8868651Skris } 8968651Skris } 9068651Skris } 9168651Skris close IN; 9268651Skris return ($is_cert, $is_crl); 9368651Skris} 9468651Skris 9568651Skris 9668651Skris# Link a certificate to its subject name hash value, each hash is of 9768651Skris# the form <hash>.<n> where n is an integer. If the hash value already exists 9868651Skris# then we need to up the value of n, unless its a duplicate in which 9968651Skris# case we skip the link. We check for duplicates by comparing the 10068651Skris# certificate fingerprints 10168651Skris 10268651Skrissub link_hash_cert { 10368651Skris my $fname = $_[0]; 104109998Smarkm $fname =~ s/'/'\\''/g; 105109998Smarkm my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in '$fname'`; 10668651Skris chomp $hash; 10768651Skris chomp $fprint; 10868651Skris $fprint =~ s/^.*=//; 10968651Skris $fprint =~ tr/://d; 11068651Skris my $suffix = 0; 11168651Skris # Search for an unused hash filename 11268651Skris while(exists $hashlist{"$hash.$suffix"}) { 11368651Skris # Hash matches: if fingerprint matches its a duplicate cert 11468651Skris if($hashlist{"$hash.$suffix"} eq $fprint) { 11568651Skris print STDERR "WARNING: Skipping duplicate certificate $fname\n"; 11668651Skris return; 11768651Skris } 11868651Skris $suffix++; 11968651Skris } 12068651Skris $hash .= ".$suffix"; 12168651Skris print "$fname => $hash\n"; 12276866Skris $symlink_exists=eval {symlink("",""); 1}; 12376866Skris if ($symlink_exists) { 12476866Skris symlink $fname, $hash; 12576866Skris } else { 12676866Skris system ("cp", $fname, $hash); 12776866Skris } 12868651Skris $hashlist{$hash} = $fprint; 12968651Skris} 13068651Skris 13168651Skris# Same as above except for a CRL. CRL links are of the form <hash>.r<n> 13268651Skris 13368651Skrissub link_hash_crl { 13468651Skris my $fname = $_[0]; 135109998Smarkm $fname =~ s/'/'\\''/g; 136109998Smarkm my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`; 13768651Skris chomp $hash; 13868651Skris chomp $fprint; 13968651Skris $fprint =~ s/^.*=//; 14068651Skris $fprint =~ tr/://d; 14168651Skris my $suffix = 0; 14268651Skris # Search for an unused hash filename 14368651Skris while(exists $hashlist{"$hash.r$suffix"}) { 14468651Skris # Hash matches: if fingerprint matches its a duplicate cert 14568651Skris if($hashlist{"$hash.r$suffix"} eq $fprint) { 14668651Skris print STDERR "WARNING: Skipping duplicate CRL $fname\n"; 14768651Skris return; 14868651Skris } 14968651Skris $suffix++; 15068651Skris } 15168651Skris $hash .= ".r$suffix"; 15268651Skris print "$fname => $hash\n"; 15376866Skris $symlink_exists=eval {symlink("",""); 1}; 15476866Skris if ($symlink_exists) { 15576866Skris symlink $fname, $hash; 15676866Skris } else { 15776866Skris system ("cp", $fname, $hash); 15876866Skris } 15968651Skris $hashlist{$hash} = $fprint; 16068651Skris} 16168651Skris 162