ca3021ae8a4ff2ccf1a2f121a60f8ba6e20c9aef
[openssl.git] / tools / c_rehash.in
1 #!/usr/local/bin/perl
2
3
4 # Perl c_rehash script, scan all files in a directory
5 # and add symbolic links to their hash values.
6
7 my $openssl;
8
9 my $dir;
10
11 if(defined $ENV{OPENSSL}) {
12         $openssl = $ENV{OPENSSL};
13 } else {
14         $openssl = "openssl";
15         $ENV{OPENSSL} = $openssl;
16 }
17
18 my $pwd = `pwd`; chomp $pwd;
19 my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; # DOS/Win32 or Unix delimiter?
20
21 $ENV{PATH} .= "$path_delim$dir/bin";
22
23 if(! -x $openssl) {
24         my $found = 0;
25         foreach (split /$path_delim/, $ENV{PATH}) {
26                 if(-x "$_/$openssl") {
27                         $found = 1;
28                         last;
29                 }       
30         }
31         if($found == 0) {
32                 print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
33                 exit 0;
34         }
35 }
36
37 if(@ARGV) {
38         @dirlist = @ARGV;
39 } elsif($ENV{SSL_CERT_DIR}) {
40         @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR};
41 } else {
42         $dirlist[0] = "$dir/certs";
43 }
44
45 if (-d $dirlist[0]) {
46         chdir $dirlist[0];
47         $openssl="$pwd/$openssl" if (!-x $openssl);
48         chdir $pwd;
49 }
50
51 foreach (@dirlist) {
52         if(-d $_ and -w $_) {
53                 hash_dir($_);
54         }
55 }
56
57 sub hash_dir {
58         my %hashlist;
59         print "Doing $_[0]\n";
60         chdir $_[0];
61         opendir(DIR, ".");
62         my @flist = readdir(DIR);
63         # Delete any existing symbolic links
64         foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
65                 if(-l $_) {
66                         unlink $_;
67                 }
68         }
69         closedir DIR;
70         FILE: foreach $fname (grep {/\.pem$/} @flist) {
71                 # Check to see if certificates and/or CRLs present.
72                 my ($cert, $crl) = check_file($fname);
73                 if(!$cert && !$crl) {
74                         print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
75                         next;
76                 }
77                 link_hash_cert($fname) if($cert);
78                 link_hash_crl($fname) if($crl);
79         }
80 }
81
82 sub check_file {
83         my ($is_cert, $is_crl) = (0,0);
84         my $fname = $_[0];
85         open IN, $fname;
86         while(<IN>) {
87                 if(/^-----BEGIN (.*)-----/) {
88                         my $hdr = $1;
89                         if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
90                                 $is_cert = 1;
91                                 last if($is_crl);
92                         } elsif($hdr eq "X509 CRL") {
93                                 $is_crl = 1;
94                                 last if($is_cert);
95                         }
96                 }
97         }
98         close IN;
99         return ($is_cert, $is_crl);
100 }
101
102
103 # Link a certificate to its subject name hash value, each hash is of
104 # the form <hash>.<n> where n is an integer. If the hash value already exists
105 # then we need to up the value of n, unless its a duplicate in which
106 # case we skip the link. We check for duplicates by comparing the
107 # certificate fingerprints
108
109 sub link_hash_cert {
110                 my $fname = $_[0];
111                 $fname =~ s/'/'\\''/g;
112                 my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in "$fname"`;
113                 chomp $hash;
114                 chomp $fprint;
115                 $fprint =~ s/^.*=//;
116                 $fprint =~ tr/://d;
117                 my $suffix = 0;
118                 # Search for an unused hash filename
119                 while(exists $hashlist{"$hash.$suffix"}) {
120                         # Hash matches: if fingerprint matches its a duplicate cert
121                         if($hashlist{"$hash.$suffix"} eq $fprint) {
122                                 print STDERR "WARNING: Skipping duplicate certificate $fname\n";
123                                 return;
124                         }
125                         $suffix++;
126                 }
127                 $hash .= ".$suffix";
128                 print "$fname => $hash\n";
129                 $symlink_exists=eval {symlink("",""); 1};
130                 if ($symlink_exists) {
131                         symlink $fname, $hash;
132                 } else {
133                         open IN,"<$fname" or die "can't open $fname for read";
134                         open OUT,">$hash" or die "can't open $hash for write";
135                         print OUT <IN>; # does the job for small text files
136                         close OUT;
137                         close IN;
138                 }
139                 $hashlist{$hash} = $fprint;
140 }
141
142 # Same as above except for a CRL. CRL links are of the form <hash>.r<n>
143
144 sub link_hash_crl {
145                 my $fname = $_[0];
146                 $fname =~ s/'/'\\''/g;
147                 my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`;
148                 chomp $hash;
149                 chomp $fprint;
150                 $fprint =~ s/^.*=//;
151                 $fprint =~ tr/://d;
152                 my $suffix = 0;
153                 # Search for an unused hash filename
154                 while(exists $hashlist{"$hash.r$suffix"}) {
155                         # Hash matches: if fingerprint matches its a duplicate cert
156                         if($hashlist{"$hash.r$suffix"} eq $fprint) {
157                                 print STDERR "WARNING: Skipping duplicate CRL $fname\n";
158                                 return;
159                         }
160                         $suffix++;
161                 }
162                 $hash .= ".r$suffix";
163                 print "$fname => $hash\n";
164                 $symlink_exists=eval {symlink("",""); 1};
165                 if ($symlink_exists) {
166                         symlink $fname, $hash;
167                 } else {
168                         system ("cp", $fname, $hash);
169                 }
170                 $hashlist{$hash} = $fprint;
171 }
172