c_rehash.in 6.1 KB

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