1*267f8c1fSEnji Cooper#!/usr/bin/env perl 24757b351SPierre Pronchery 34757b351SPierre Pronchery# WARNING: do not edit! 44757b351SPierre Pronchery# Generated by Makefile from tools/c_rehash.in 54757b351SPierre Pronchery# Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved. 64757b351SPierre Pronchery# 74757b351SPierre Pronchery# Licensed under the Apache License 2.0 (the "License"). You may not use 84757b351SPierre Pronchery# this file except in compliance with the License. You can obtain a copy 94757b351SPierre Pronchery# in the file LICENSE in the source distribution or at 104757b351SPierre Pronchery# https://www.openssl.org/source/license.html 114757b351SPierre Pronchery 124757b351SPierre Pronchery# Perl c_rehash script, scan all files in a directory 134757b351SPierre Pronchery# and add symbolic links to their hash values. 144757b351SPierre Pronchery 15*267f8c1fSEnji Coopermy $dir = "etc"; 16*267f8c1fSEnji Coopermy $prefix = "/usr"; 174757b351SPierre Pronchery 184757b351SPierre Proncherymy $errorcount = 0; 194757b351SPierre Proncherymy $openssl = $ENV{OPENSSL} || "openssl"; 204757b351SPierre Proncherymy $pwd; 214757b351SPierre Proncherymy $x509hash = "-subject_hash"; 224757b351SPierre Proncherymy $crlhash = "-hash"; 234757b351SPierre Proncherymy $verbose = 0; 244757b351SPierre Proncherymy $symlink_exists=eval {symlink("",""); 1}; 254757b351SPierre Proncherymy $removelinks = 1; 264757b351SPierre Pronchery 274757b351SPierre Pronchery## Parse flags. 284757b351SPierre Proncherywhile ( $ARGV[0] =~ /^-/ ) { 294757b351SPierre Pronchery my $flag = shift @ARGV; 304757b351SPierre Pronchery last if ( $flag eq '--'); 314757b351SPierre Pronchery if ( $flag eq '-old') { 324757b351SPierre Pronchery $x509hash = "-subject_hash_old"; 334757b351SPierre Pronchery $crlhash = "-hash_old"; 344757b351SPierre Pronchery } elsif ( $flag eq '-h' || $flag eq '-help' ) { 354757b351SPierre Pronchery help(); 364757b351SPierre Pronchery } elsif ( $flag eq '-n' ) { 374757b351SPierre Pronchery $removelinks = 0; 384757b351SPierre Pronchery } elsif ( $flag eq '-v' ) { 394757b351SPierre Pronchery $verbose++; 404757b351SPierre Pronchery } 414757b351SPierre Pronchery else { 424757b351SPierre Pronchery print STDERR "Usage error; try -h.\n"; 434757b351SPierre Pronchery exit 1; 444757b351SPierre Pronchery } 454757b351SPierre Pronchery} 464757b351SPierre Pronchery 474757b351SPierre Proncherysub help { 484757b351SPierre Pronchery print "Usage: c_rehash [-old] [-h] [-help] [-v] [dirs...]\n"; 494757b351SPierre Pronchery print " -old use old-style digest\n"; 504757b351SPierre Pronchery print " -h or -help print this help text\n"; 514757b351SPierre Pronchery print " -v print files removed and linked\n"; 524757b351SPierre Pronchery exit 0; 534757b351SPierre Pronchery} 544757b351SPierre Pronchery 554757b351SPierre Proncheryeval "require Cwd"; 564757b351SPierre Proncheryif (defined(&Cwd::getcwd)) { 574757b351SPierre Pronchery $pwd=Cwd::getcwd(); 584757b351SPierre Pronchery} else { 594757b351SPierre Pronchery $pwd=`pwd`; 604757b351SPierre Pronchery chomp($pwd); 614757b351SPierre Pronchery} 624757b351SPierre Pronchery 634757b351SPierre Pronchery# DOS/Win32 or Unix delimiter? Prefix our installdir, then search. 644757b351SPierre Proncherymy $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; 654757b351SPierre Pronchery$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : ""); 664757b351SPierre Pronchery 674757b351SPierre Proncheryif (!(-f $openssl && -x $openssl)) { 684757b351SPierre Pronchery my $found = 0; 694757b351SPierre Pronchery foreach (split /$path_delim/, $ENV{PATH}) { 704757b351SPierre Pronchery if (-f "$_/$openssl" && -x "$_/$openssl") { 714757b351SPierre Pronchery $found = 1; 724757b351SPierre Pronchery $openssl = "$_/$openssl"; 734757b351SPierre Pronchery last; 744757b351SPierre Pronchery } 754757b351SPierre Pronchery } 764757b351SPierre Pronchery if ($found == 0) { 774757b351SPierre Pronchery print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n"; 784757b351SPierre Pronchery exit 0; 794757b351SPierre Pronchery } 804757b351SPierre Pronchery} 814757b351SPierre Pronchery 824757b351SPierre Proncheryif (@ARGV) { 834757b351SPierre Pronchery @dirlist = @ARGV; 844757b351SPierre Pronchery} elsif ($ENV{SSL_CERT_DIR}) { 854757b351SPierre Pronchery @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR}; 864757b351SPierre Pronchery} else { 874757b351SPierre Pronchery $dirlist[0] = "$dir/certs"; 884757b351SPierre Pronchery} 894757b351SPierre Pronchery 904757b351SPierre Proncheryif (-d $dirlist[0]) { 914757b351SPierre Pronchery chdir $dirlist[0]; 924757b351SPierre Pronchery $openssl="$pwd/$openssl" if (!(-f $openssl && -x $openssl)); 934757b351SPierre Pronchery chdir $pwd; 944757b351SPierre Pronchery} 954757b351SPierre Pronchery 964757b351SPierre Proncheryforeach (@dirlist) { 974757b351SPierre Pronchery if (-d $_ ) { 984757b351SPierre Pronchery if ( -w $_) { 994757b351SPierre Pronchery hash_dir($_); 1004757b351SPierre Pronchery } else { 1014757b351SPierre Pronchery print "Skipping $_, can't write\n"; 1024757b351SPierre Pronchery $errorcount++; 1034757b351SPierre Pronchery } 1044757b351SPierre Pronchery } 1054757b351SPierre Pronchery} 1064757b351SPierre Proncheryexit($errorcount); 1074757b351SPierre Pronchery 1084757b351SPierre Proncherysub copy_file { 1094757b351SPierre Pronchery my ($src_fname, $dst_fname) = @_; 1104757b351SPierre Pronchery 1114757b351SPierre Pronchery if (open(my $in, "<", $src_fname)) { 1124757b351SPierre Pronchery if (open(my $out, ">", $dst_fname)) { 1134757b351SPierre Pronchery print $out $_ while (<$in>); 1144757b351SPierre Pronchery close $out; 1154757b351SPierre Pronchery } else { 1164757b351SPierre Pronchery warn "Cannot open $dst_fname for write, $!"; 1174757b351SPierre Pronchery } 1184757b351SPierre Pronchery close $in; 1194757b351SPierre Pronchery } else { 1204757b351SPierre Pronchery warn "Cannot open $src_fname for read, $!"; 1214757b351SPierre Pronchery } 1224757b351SPierre Pronchery} 1234757b351SPierre Pronchery 1244757b351SPierre Proncherysub hash_dir { 1254757b351SPierre Pronchery my $dir = shift; 1264757b351SPierre Pronchery my %hashlist; 1274757b351SPierre Pronchery 1284757b351SPierre Pronchery print "Doing $dir\n"; 1294757b351SPierre Pronchery 1304757b351SPierre Pronchery if (!chdir $dir) { 1314757b351SPierre Pronchery print STDERR "WARNING: Cannot chdir to '$dir', $!\n"; 1324757b351SPierre Pronchery return; 1334757b351SPierre Pronchery } 1344757b351SPierre Pronchery 1354757b351SPierre Pronchery opendir(DIR, ".") || print STDERR "WARNING: Cannot opendir '.', $!\n"; 1364757b351SPierre Pronchery my @flist = sort readdir(DIR); 1374757b351SPierre Pronchery closedir DIR; 1384757b351SPierre Pronchery if ( $removelinks ) { 1394757b351SPierre Pronchery # Delete any existing symbolic links 1404757b351SPierre Pronchery foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) { 1414757b351SPierre Pronchery if (-l $_) { 1424757b351SPierre Pronchery print "unlink $_\n" if $verbose; 1434757b351SPierre Pronchery unlink $_ || warn "Can't unlink $_, $!\n"; 1444757b351SPierre Pronchery } 1454757b351SPierre Pronchery } 1464757b351SPierre Pronchery } 1474757b351SPierre Pronchery FILE: foreach $fname (grep {/\.(pem|crt|cer|crl)$/} @flist) { 1484757b351SPierre Pronchery # Check to see if certificates and/or CRLs present. 1494757b351SPierre Pronchery my ($cert, $crl) = check_file($fname); 1504757b351SPierre Pronchery if (!$cert && !$crl) { 1514757b351SPierre Pronchery print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n"; 1524757b351SPierre Pronchery next; 1534757b351SPierre Pronchery } 1544757b351SPierre Pronchery link_hash_cert($fname) if ($cert); 1554757b351SPierre Pronchery link_hash_crl($fname) if ($crl); 1564757b351SPierre Pronchery } 1574757b351SPierre Pronchery 1584757b351SPierre Pronchery chdir $pwd; 1594757b351SPierre Pronchery} 1604757b351SPierre Pronchery 1614757b351SPierre Proncherysub check_file { 1624757b351SPierre Pronchery my ($is_cert, $is_crl) = (0,0); 1634757b351SPierre Pronchery my $fname = $_[0]; 1644757b351SPierre Pronchery 1654757b351SPierre Pronchery open(my $in, "<", $fname); 1664757b351SPierre Pronchery while(<$in>) { 1674757b351SPierre Pronchery if (/^-----BEGIN (.*)-----/) { 1684757b351SPierre Pronchery my $hdr = $1; 1694757b351SPierre Pronchery if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) { 1704757b351SPierre Pronchery $is_cert = 1; 1714757b351SPierre Pronchery last if ($is_crl); 1724757b351SPierre Pronchery } elsif ($hdr eq "X509 CRL") { 1734757b351SPierre Pronchery $is_crl = 1; 1744757b351SPierre Pronchery last if ($is_cert); 1754757b351SPierre Pronchery } 1764757b351SPierre Pronchery } 1774757b351SPierre Pronchery } 1784757b351SPierre Pronchery close $in; 1794757b351SPierre Pronchery return ($is_cert, $is_crl); 1804757b351SPierre Pronchery} 1814757b351SPierre Pronchery 1824757b351SPierre Proncherysub compute_hash { 1834757b351SPierre Pronchery my $fh; 1844757b351SPierre Pronchery if ( $^O eq "VMS" ) { 1854757b351SPierre Pronchery # VMS uses the open through shell 1864757b351SPierre Pronchery # The file names are safe there and list form is unsupported 1874757b351SPierre Pronchery if (!open($fh, "-|", join(' ', @_))) { 1884757b351SPierre Pronchery print STDERR "Cannot compute hash on '$fname'\n"; 1894757b351SPierre Pronchery return; 1904757b351SPierre Pronchery } 1914757b351SPierre Pronchery } else { 1924757b351SPierre Pronchery if (!open($fh, "-|", @_)) { 1934757b351SPierre Pronchery print STDERR "Cannot compute hash on '$fname'\n"; 1944757b351SPierre Pronchery return; 1954757b351SPierre Pronchery } 1964757b351SPierre Pronchery } 1974757b351SPierre Pronchery return (<$fh>, <$fh>); 1984757b351SPierre Pronchery} 1994757b351SPierre Pronchery 2004757b351SPierre Pronchery# Link a certificate to its subject name hash value, each hash is of 2014757b351SPierre Pronchery# the form <hash>.<n> where n is an integer. If the hash value already exists 2024757b351SPierre Pronchery# then we need to up the value of n, unless its a duplicate in which 2034757b351SPierre Pronchery# case we skip the link. We check for duplicates by comparing the 2044757b351SPierre Pronchery# certificate fingerprints 2054757b351SPierre Pronchery 2064757b351SPierre Proncherysub link_hash_cert { 2074757b351SPierre Pronchery link_hash($_[0], 'cert'); 2084757b351SPierre Pronchery} 2094757b351SPierre Pronchery 2104757b351SPierre Pronchery# Same as above except for a CRL. CRL links are of the form <hash>.r<n> 2114757b351SPierre Pronchery 2124757b351SPierre Proncherysub link_hash_crl { 2134757b351SPierre Pronchery link_hash($_[0], 'crl'); 2144757b351SPierre Pronchery} 2154757b351SPierre Pronchery 2164757b351SPierre Proncherysub link_hash { 2174757b351SPierre Pronchery my ($fname, $type) = @_; 2184757b351SPierre Pronchery my $is_cert = $type eq 'cert'; 2194757b351SPierre Pronchery 2204757b351SPierre Pronchery my ($hash, $fprint) = compute_hash($openssl, 2214757b351SPierre Pronchery $is_cert ? "x509" : "crl", 2224757b351SPierre Pronchery $is_cert ? $x509hash : $crlhash, 2234757b351SPierre Pronchery "-fingerprint", "-noout", 2244757b351SPierre Pronchery "-in", $fname); 2254757b351SPierre Pronchery chomp $hash; 2264757b351SPierre Pronchery $hash =~ s/^.*=// if !$is_cert; 2274757b351SPierre Pronchery chomp $fprint; 2284757b351SPierre Pronchery return if !$hash; 2294757b351SPierre Pronchery $fprint =~ s/^.*=//; 2304757b351SPierre Pronchery $fprint =~ tr/://d; 2314757b351SPierre Pronchery my $suffix = 0; 2324757b351SPierre Pronchery # Search for an unused hash filename 2334757b351SPierre Pronchery my $crlmark = $is_cert ? "" : "r"; 2344757b351SPierre Pronchery while(exists $hashlist{"$hash.$crlmark$suffix"}) { 2354757b351SPierre Pronchery # Hash matches: if fingerprint matches its a duplicate cert 2364757b351SPierre Pronchery if ($hashlist{"$hash.$crlmark$suffix"} eq $fprint) { 2374757b351SPierre Pronchery my $what = $is_cert ? 'certificate' : 'CRL'; 2384757b351SPierre Pronchery print STDERR "WARNING: Skipping duplicate $what $fname\n"; 2394757b351SPierre Pronchery return; 2404757b351SPierre Pronchery } 2414757b351SPierre Pronchery $suffix++; 2424757b351SPierre Pronchery } 2434757b351SPierre Pronchery $hash .= ".$crlmark$suffix"; 2444757b351SPierre Pronchery if ($symlink_exists) { 2454757b351SPierre Pronchery print "link $fname -> $hash\n" if $verbose; 2464757b351SPierre Pronchery symlink $fname, $hash || warn "Can't symlink, $!"; 2474757b351SPierre Pronchery } else { 2484757b351SPierre Pronchery print "copy $fname -> $hash\n" if $verbose; 2494757b351SPierre Pronchery copy_file($fname, $hash); 2504757b351SPierre Pronchery } 2514757b351SPierre Pronchery $hashlist{$hash} = $fprint; 2524757b351SPierre Pronchery} 253