1*4757b351SPierre Pronchery#!/usr/local/bin/perl 2*4757b351SPierre Pronchery 3*4757b351SPierre Pronchery# WARNING: do not edit! 4*4757b351SPierre Pronchery# Generated by Makefile from tools/c_rehash.in 5*4757b351SPierre Pronchery# Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved. 6*4757b351SPierre Pronchery# 7*4757b351SPierre Pronchery# Licensed under the Apache License 2.0 (the "License"). You may not use 8*4757b351SPierre Pronchery# this file except in compliance with the License. You can obtain a copy 9*4757b351SPierre Pronchery# in the file LICENSE in the source distribution or at 10*4757b351SPierre Pronchery# https://www.openssl.org/source/license.html 11*4757b351SPierre Pronchery 12*4757b351SPierre Pronchery# Perl c_rehash script, scan all files in a directory 13*4757b351SPierre Pronchery# and add symbolic links to their hash values. 14*4757b351SPierre Pronchery 15*4757b351SPierre Proncherymy $dir = "/usr/local/openssl"; 16*4757b351SPierre Proncherymy $prefix = "/usr/local"; 17*4757b351SPierre Pronchery 18*4757b351SPierre Proncherymy $errorcount = 0; 19*4757b351SPierre Proncherymy $openssl = $ENV{OPENSSL} || "openssl"; 20*4757b351SPierre Proncherymy $pwd; 21*4757b351SPierre Proncherymy $x509hash = "-subject_hash"; 22*4757b351SPierre Proncherymy $crlhash = "-hash"; 23*4757b351SPierre Proncherymy $verbose = 0; 24*4757b351SPierre Proncherymy $symlink_exists=eval {symlink("",""); 1}; 25*4757b351SPierre Proncherymy $removelinks = 1; 26*4757b351SPierre Pronchery 27*4757b351SPierre Pronchery## Parse flags. 28*4757b351SPierre Proncherywhile ( $ARGV[0] =~ /^-/ ) { 29*4757b351SPierre Pronchery my $flag = shift @ARGV; 30*4757b351SPierre Pronchery last if ( $flag eq '--'); 31*4757b351SPierre Pronchery if ( $flag eq '-old') { 32*4757b351SPierre Pronchery $x509hash = "-subject_hash_old"; 33*4757b351SPierre Pronchery $crlhash = "-hash_old"; 34*4757b351SPierre Pronchery } elsif ( $flag eq '-h' || $flag eq '-help' ) { 35*4757b351SPierre Pronchery help(); 36*4757b351SPierre Pronchery } elsif ( $flag eq '-n' ) { 37*4757b351SPierre Pronchery $removelinks = 0; 38*4757b351SPierre Pronchery } elsif ( $flag eq '-v' ) { 39*4757b351SPierre Pronchery $verbose++; 40*4757b351SPierre Pronchery } 41*4757b351SPierre Pronchery else { 42*4757b351SPierre Pronchery print STDERR "Usage error; try -h.\n"; 43*4757b351SPierre Pronchery exit 1; 44*4757b351SPierre Pronchery } 45*4757b351SPierre Pronchery} 46*4757b351SPierre Pronchery 47*4757b351SPierre Proncherysub help { 48*4757b351SPierre Pronchery print "Usage: c_rehash [-old] [-h] [-help] [-v] [dirs...]\n"; 49*4757b351SPierre Pronchery print " -old use old-style digest\n"; 50*4757b351SPierre Pronchery print " -h or -help print this help text\n"; 51*4757b351SPierre Pronchery print " -v print files removed and linked\n"; 52*4757b351SPierre Pronchery exit 0; 53*4757b351SPierre Pronchery} 54*4757b351SPierre Pronchery 55*4757b351SPierre Proncheryeval "require Cwd"; 56*4757b351SPierre Proncheryif (defined(&Cwd::getcwd)) { 57*4757b351SPierre Pronchery $pwd=Cwd::getcwd(); 58*4757b351SPierre Pronchery} else { 59*4757b351SPierre Pronchery $pwd=`pwd`; 60*4757b351SPierre Pronchery chomp($pwd); 61*4757b351SPierre Pronchery} 62*4757b351SPierre Pronchery 63*4757b351SPierre Pronchery# DOS/Win32 or Unix delimiter? Prefix our installdir, then search. 64*4757b351SPierre Proncherymy $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; 65*4757b351SPierre Pronchery$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : ""); 66*4757b351SPierre Pronchery 67*4757b351SPierre Proncheryif (!(-f $openssl && -x $openssl)) { 68*4757b351SPierre Pronchery my $found = 0; 69*4757b351SPierre Pronchery foreach (split /$path_delim/, $ENV{PATH}) { 70*4757b351SPierre Pronchery if (-f "$_/$openssl" && -x "$_/$openssl") { 71*4757b351SPierre Pronchery $found = 1; 72*4757b351SPierre Pronchery $openssl = "$_/$openssl"; 73*4757b351SPierre Pronchery last; 74*4757b351SPierre Pronchery } 75*4757b351SPierre Pronchery } 76*4757b351SPierre Pronchery if ($found == 0) { 77*4757b351SPierre Pronchery print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n"; 78*4757b351SPierre Pronchery exit 0; 79*4757b351SPierre Pronchery } 80*4757b351SPierre Pronchery} 81*4757b351SPierre Pronchery 82*4757b351SPierre Proncheryif (@ARGV) { 83*4757b351SPierre Pronchery @dirlist = @ARGV; 84*4757b351SPierre Pronchery} elsif ($ENV{SSL_CERT_DIR}) { 85*4757b351SPierre Pronchery @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR}; 86*4757b351SPierre Pronchery} else { 87*4757b351SPierre Pronchery $dirlist[0] = "$dir/certs"; 88*4757b351SPierre Pronchery} 89*4757b351SPierre Pronchery 90*4757b351SPierre Proncheryif (-d $dirlist[0]) { 91*4757b351SPierre Pronchery chdir $dirlist[0]; 92*4757b351SPierre Pronchery $openssl="$pwd/$openssl" if (!(-f $openssl && -x $openssl)); 93*4757b351SPierre Pronchery chdir $pwd; 94*4757b351SPierre Pronchery} 95*4757b351SPierre Pronchery 96*4757b351SPierre Proncheryforeach (@dirlist) { 97*4757b351SPierre Pronchery if (-d $_ ) { 98*4757b351SPierre Pronchery if ( -w $_) { 99*4757b351SPierre Pronchery hash_dir($_); 100*4757b351SPierre Pronchery } else { 101*4757b351SPierre Pronchery print "Skipping $_, can't write\n"; 102*4757b351SPierre Pronchery $errorcount++; 103*4757b351SPierre Pronchery } 104*4757b351SPierre Pronchery } 105*4757b351SPierre Pronchery} 106*4757b351SPierre Proncheryexit($errorcount); 107*4757b351SPierre Pronchery 108*4757b351SPierre Proncherysub copy_file { 109*4757b351SPierre Pronchery my ($src_fname, $dst_fname) = @_; 110*4757b351SPierre Pronchery 111*4757b351SPierre Pronchery if (open(my $in, "<", $src_fname)) { 112*4757b351SPierre Pronchery if (open(my $out, ">", $dst_fname)) { 113*4757b351SPierre Pronchery print $out $_ while (<$in>); 114*4757b351SPierre Pronchery close $out; 115*4757b351SPierre Pronchery } else { 116*4757b351SPierre Pronchery warn "Cannot open $dst_fname for write, $!"; 117*4757b351SPierre Pronchery } 118*4757b351SPierre Pronchery close $in; 119*4757b351SPierre Pronchery } else { 120*4757b351SPierre Pronchery warn "Cannot open $src_fname for read, $!"; 121*4757b351SPierre Pronchery } 122*4757b351SPierre Pronchery} 123*4757b351SPierre Pronchery 124*4757b351SPierre Proncherysub hash_dir { 125*4757b351SPierre Pronchery my $dir = shift; 126*4757b351SPierre Pronchery my %hashlist; 127*4757b351SPierre Pronchery 128*4757b351SPierre Pronchery print "Doing $dir\n"; 129*4757b351SPierre Pronchery 130*4757b351SPierre Pronchery if (!chdir $dir) { 131*4757b351SPierre Pronchery print STDERR "WARNING: Cannot chdir to '$dir', $!\n"; 132*4757b351SPierre Pronchery return; 133*4757b351SPierre Pronchery } 134*4757b351SPierre Pronchery 135*4757b351SPierre Pronchery opendir(DIR, ".") || print STDERR "WARNING: Cannot opendir '.', $!\n"; 136*4757b351SPierre Pronchery my @flist = sort readdir(DIR); 137*4757b351SPierre Pronchery closedir DIR; 138*4757b351SPierre Pronchery if ( $removelinks ) { 139*4757b351SPierre Pronchery # Delete any existing symbolic links 140*4757b351SPierre Pronchery foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { 141*4757b351SPierre Pronchery if (-l $_) { 142*4757b351SPierre Pronchery print "unlink $_\n" if $verbose; 143*4757b351SPierre Pronchery unlink $_ || warn "Can't unlink $_, $!\n"; 144*4757b351SPierre Pronchery } 145*4757b351SPierre Pronchery } 146*4757b351SPierre Pronchery } 147*4757b351SPierre Pronchery FILE: foreach $fname (grep {/\.(pem|crt|cer|crl)$/} @flist) { 148*4757b351SPierre Pronchery # Check to see if certificates and/or CRLs present. 149*4757b351SPierre Pronchery my ($cert, $crl) = check_file($fname); 150*4757b351SPierre Pronchery if (!$cert && !$crl) { 151*4757b351SPierre Pronchery print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; 152*4757b351SPierre Pronchery next; 153*4757b351SPierre Pronchery } 154*4757b351SPierre Pronchery link_hash_cert($fname) if ($cert); 155*4757b351SPierre Pronchery link_hash_crl($fname) if ($crl); 156*4757b351SPierre Pronchery } 157*4757b351SPierre Pronchery 158*4757b351SPierre Pronchery chdir $pwd; 159*4757b351SPierre Pronchery} 160*4757b351SPierre Pronchery 161*4757b351SPierre Proncherysub check_file { 162*4757b351SPierre Pronchery my ($is_cert, $is_crl) = (0,0); 163*4757b351SPierre Pronchery my $fname = $_[0]; 164*4757b351SPierre Pronchery 165*4757b351SPierre Pronchery open(my $in, "<", $fname); 166*4757b351SPierre Pronchery while(<$in>) { 167*4757b351SPierre Pronchery if (/^-----BEGIN (.*)-----/) { 168*4757b351SPierre Pronchery my $hdr = $1; 169*4757b351SPierre Pronchery if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) { 170*4757b351SPierre Pronchery $is_cert = 1; 171*4757b351SPierre Pronchery last if ($is_crl); 172*4757b351SPierre Pronchery } elsif ($hdr eq "X509 CRL") { 173*4757b351SPierre Pronchery $is_crl = 1; 174*4757b351SPierre Pronchery last if ($is_cert); 175*4757b351SPierre Pronchery } 176*4757b351SPierre Pronchery } 177*4757b351SPierre Pronchery } 178*4757b351SPierre Pronchery close $in; 179*4757b351SPierre Pronchery return ($is_cert, $is_crl); 180*4757b351SPierre Pronchery} 181*4757b351SPierre Pronchery 182*4757b351SPierre Proncherysub compute_hash { 183*4757b351SPierre Pronchery my $fh; 184*4757b351SPierre Pronchery if ( $^O eq "VMS" ) { 185*4757b351SPierre Pronchery # VMS uses the open through shell 186*4757b351SPierre Pronchery # The file names are safe there and list form is unsupported 187*4757b351SPierre Pronchery if (!open($fh, "-|", join(' ', @_))) { 188*4757b351SPierre Pronchery print STDERR "Cannot compute hash on '$fname'\n"; 189*4757b351SPierre Pronchery return; 190*4757b351SPierre Pronchery } 191*4757b351SPierre Pronchery } else { 192*4757b351SPierre Pronchery if (!open($fh, "-|", @_)) { 193*4757b351SPierre Pronchery print STDERR "Cannot compute hash on '$fname'\n"; 194*4757b351SPierre Pronchery return; 195*4757b351SPierre Pronchery } 196*4757b351SPierre Pronchery } 197*4757b351SPierre Pronchery return (<$fh>, <$fh>); 198*4757b351SPierre Pronchery} 199*4757b351SPierre Pronchery 200*4757b351SPierre Pronchery# Link a certificate to its subject name hash value, each hash is of 201*4757b351SPierre Pronchery# the form <hash>.<n> where n is an integer. If the hash value already exists 202*4757b351SPierre Pronchery# then we need to up the value of n, unless its a duplicate in which 203*4757b351SPierre Pronchery# case we skip the link. We check for duplicates by comparing the 204*4757b351SPierre Pronchery# certificate fingerprints 205*4757b351SPierre Pronchery 206*4757b351SPierre Proncherysub link_hash_cert { 207*4757b351SPierre Pronchery link_hash($_[0], 'cert'); 208*4757b351SPierre Pronchery} 209*4757b351SPierre Pronchery 210*4757b351SPierre Pronchery# Same as above except for a CRL. CRL links are of the form <hash>.r<n> 211*4757b351SPierre Pronchery 212*4757b351SPierre Proncherysub link_hash_crl { 213*4757b351SPierre Pronchery link_hash($_[0], 'crl'); 214*4757b351SPierre Pronchery} 215*4757b351SPierre Pronchery 216*4757b351SPierre Proncherysub link_hash { 217*4757b351SPierre Pronchery my ($fname, $type) = @_; 218*4757b351SPierre Pronchery my $is_cert = $type eq 'cert'; 219*4757b351SPierre Pronchery 220*4757b351SPierre Pronchery my ($hash, $fprint) = compute_hash($openssl, 221*4757b351SPierre Pronchery $is_cert ? "x509" : "crl", 222*4757b351SPierre Pronchery $is_cert ? $x509hash : $crlhash, 223*4757b351SPierre Pronchery "-fingerprint", "-noout", 224*4757b351SPierre Pronchery "-in", $fname); 225*4757b351SPierre Pronchery chomp $hash; 226*4757b351SPierre Pronchery $hash =~ s/^.*=// if !$is_cert; 227*4757b351SPierre Pronchery chomp $fprint; 228*4757b351SPierre Pronchery return if !$hash; 229*4757b351SPierre Pronchery $fprint =~ s/^.*=//; 230*4757b351SPierre Pronchery $fprint =~ tr/://d; 231*4757b351SPierre Pronchery my $suffix = 0; 232*4757b351SPierre Pronchery # Search for an unused hash filename 233*4757b351SPierre Pronchery my $crlmark = $is_cert ? "" : "r"; 234*4757b351SPierre Pronchery while(exists $hashlist{"$hash.$crlmark$suffix"}) { 235*4757b351SPierre Pronchery # Hash matches: if fingerprint matches its a duplicate cert 236*4757b351SPierre Pronchery if ($hashlist{"$hash.$crlmark$suffix"} eq $fprint) { 237*4757b351SPierre Pronchery my $what = $is_cert ? 'certificate' : 'CRL'; 238*4757b351SPierre Pronchery print STDERR "WARNING: Skipping duplicate $what $fname\n"; 239*4757b351SPierre Pronchery return; 240*4757b351SPierre Pronchery } 241*4757b351SPierre Pronchery $suffix++; 242*4757b351SPierre Pronchery } 243*4757b351SPierre Pronchery $hash .= ".$crlmark$suffix"; 244*4757b351SPierre Pronchery if ($symlink_exists) { 245*4757b351SPierre Pronchery print "link $fname -> $hash\n" if $verbose; 246*4757b351SPierre Pronchery symlink $fname, $hash || warn "Can't symlink, $!"; 247*4757b351SPierre Pronchery } else { 248*4757b351SPierre Pronchery print "copy $fname -> $hash\n" if $verbose; 249*4757b351SPierre Pronchery copy_file($fname, $hash); 250*4757b351SPierre Pronchery } 251*4757b351SPierre Pronchery $hashlist{$hash} = $fprint; 252*4757b351SPierre Pronchery} 253